perm filename MIX1[MIX,SYS] blob sn#200557 filedate 1976-02-07 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00058 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00007 00002	TITLE	MIX
C00013 00003	COMMENT		Registers 0-7 and 15 are used to simulate MIX's
C00016 00004		SUBTTL	MIXLOG - LOG OF ADDITIONS AND CORRECTIONS
C00029 00005		SUBTTL	MIXDPY	- III manipulations
C00034 00006	COMMENT		This section has all the display facilities, including
C00042 00007	COMMENT		If the PDP address of the word to be displayed is
C00045 00008		SUBTTL	MIXDD	DD manipulation routines
C00046 00009	 Update DD screen ***
C00054 00010	 Subroutine to see if a line needs to be updated
C00058 00011	COMMENT  NOW WRITE ALL INFO TO THE DATA DISK BUFFER 
C00063 00012	COMMENT  TABLES USED BY DDUPD 
C00066 00013	COMMENT  ROUTINE TO REFRESH WHOLE SCREEN 
C00067 00014		SUBTTL	MIXBUT	Handle "console buttons"
C00072 00015	QSTART:	SETZB	RJ, EXTIME			 EXTIME, RJ ← 0
C00076 00016	QSETUP:	SETZ	10,
C00079 00017	COMMENT  RESCN routine to scan the rest of the line of TTY input looking an
C00084 00018	BEGIN	MIXBUG ↔ SUBTTL MIXBUG - Dynamic debugger for MIX machine
C00088 00019	comment		INCHAR is a subroutine to read one char from the TTY and
C00090 00020	comment		SCAN is a subroutine to return one input token.  the token
C00093 00021	opdef	scan	[pushj p, .]
C00100 00022	comment		EXPR is a subroutine to read in and evaluate an expression.
C00106 00023	comment		WVAL is a subroutine to read in and evaluate a w-value.
C00111 00024	comment		FPOINT is a table of byte pointers for depositing things
C00112 00025	comment		INST is a subroutine to read an instruction.
C00116 00026	comment		ADDR is a subroutine to read an expression and see whether
C00118 00027	comment		GETSYM is a subroutine to find a symbolic expression for
C00121 00028	comment		these are a couple of subroutines to do some outputting:
C00123 00029	comment		MIXBUG is the starting address of the command interpreter.
C00125 00030	comment		EXAMIN is what looks at core locations and displays what it sees.
C00129 00031	 put out cell in symbolic instruction mode
C00137 00032	eb0:	movei	tac1, "+"		 assume positive
C00140 00033	es00:	movei	tac1,40
C00142 00034	en0:	movei	tac1,40
C00143 00035	dposit:	addrc				 get address followed by ←
C00145 00036	comment		BREAK and UBREAK are the places which handle
C00148 00037	comment		JUMPER is (would you believe) what does the jumping
C00149 00038	comment		XXXX is where we go to execute a particular instruction
C00150 00039	comment		EQUAL is used to show things in different styles
C00151 00040	comment		LF is where we display the next location
C00152 00041		SUBTTL	MIXLOK - I/O interlocking.
C00158 00042		SUBTTL	MIXMON - Central interpreter/monitor
C00161 00043	OPLST:	NOP
C00162 00044	COMMENT		Field specification:
C00163 00045	COMMENT		Memory specification:
C00165 00046	COMMENT		"Load" instructions.
C00167 00047	COMMENT		"Store" instructions.
C00170 00048	COMMENT		"Arithmetic" instructions.
C00175 00049	COMMENT		"Address transfer" insructions
C00177 00050	COMMENT		"Comparison" instructions.
C00179 00051	COMMENT		"Jump" instructions.
C00182 00052	COMMENT		Miscellaneous operators.
C00191 00053		SUBTTL	MIXIO - I/O button routines
C00195 00054	COMMENT		"Input-output" operations.
C00199 00055	COMMENT   The IN instruction  
C00203 00056	COMMENT   The OUT instruction  
C00209 00057	COMMENT		These are the device specific sections.
C00218 00058		these are the other i/o related operations
C00223 ENDMK
C⊗;
TITLE	MIX

MIXASM←←0		;flag indicating complete MIX system, not just MIXAL

COMMENT	⊗

	The summary given below is out of date:  there are many more buttons.
A full description is in the write-up:   MIX.DOC

        This is a MIX simulator.  The MIX machine being simulated has
a  byte  size  of  64.   At  present,  this  machine has virtually no
automatic input/output facilities.  However, it  does  have  numerous
console buttons with the following effects:

        "START" or "S"-- Type the word `start' followed 4  !'s;  then
                return to button mode. (When operational, this button
                will initialize the timer and  the  program  counter,
then begin execution at location 0000)

        "GO"  or  "G"--  Type  the  word `go' followed by 4 !'s; then
                return to button mode. (When operational, this button
                will  read  a  card  into  0000-0015,  then  jump  to
                location 0000)

        "LOAD" or "L"-- Type the word `load' followed by 4 !'s;  then
                return to button mode. (When operational, this button
                will read a  card  into  0000-0015,  then  return  to
                button mode)

        "CONT"  or "C"-- Type the word `cont' followed by 4 !'s; then
                begin execution at the instruction pointed to by  the
                program counter.

        "HALT"  or  "H"--  Return  to  button  mode.  To halt while a
                program is being executed, type a carriage-return.

        "STEP" or "X"-- Execute a single instruction.

        "DISP" or "D"-- Show the contents of rA, rX, rJ, the time (in
                octal and in MIX cycles) shown by the timer, the base
                address of the simulated core positions (the  address
                of  location  0000  in  octal),  the  PDP-10 location
                pointed to by  the  program  counter,  and  the  most
                recent MIX instruction executed.

        "MEM"  or  "M"--  Prepare  to read in four decimal digits and
                then type the contents of that MIX location;  if  "X"
                is typed instead of four digits, then leave "M" mode.
                (i.e., you can get several locations  each  time  you
                press "MEM")

        "ZXT"-- Zero out the timer.

        "ZPC"-- Set the program counter to location 0000.

        MIX words are represented by PDP-10 words on  a  1-1  (into?)
basis according to the following table:

		PDP-10 bits	MIX byte
		 0- 5		sign (00=+, 40=-)
		 6-11		byte 1
		12-17		byte 2
		18-23		byte 3
		24-29		byte 4
		30-35		byte 5

        Overall, the major emphasis has been on reasonable speed, but
extreme  attention  to  details, with the idea that this would not be
used for actual operation of programs to any great degree, but  would
be  used to debug compilers, and so it is important to know when some
"undefined" operation occurs.  I suspect that tables could be used to
a  greater  advantage.  I also plan to write several more subroutines
so that the amount of PDP-10 memory used by the program is decreased.
I  also  think  that  there are several areas where the code could be
significantly improved, but it is probably not worth the  expenditure
of time at this point in the game.




				Peace,



					(CS236B--June 5, 1970)

	⊗
COMMENT	⊗	Registers 0-7 and 15 are used to simulate MIX's
		rA-rX and rJ.  Registers 10-13 are work registers.
		Register 14 contains the MIX word which is the
		present instruction.  Register 16 contains the
		overflow indicator and the comparison indicator
		(bits 0-3) and a program counter (pointing to
		the next PDP-10 word to be interpreted) in bits
		13-35.  Register 17 contains the push-down pointer.
	⊗

↓RA	←0
↓R1	←1
↓R2	←2
↓R3	←3
↓R4	←4
↓R5	←5
↓R6	←6
↓RX	←7
↓RJ	←15

↓INSTR	←14
↓FLAGS	←↓PC	←16
↓P	←17

↓OVFLAG	←1B18
↓GFLAG	←1B19
↓EFLAG	←1B20
↓LFLAG	←1B21
↓SIFLAG	←1B22

REL0:				;*RES* RELOCATED ZERO, FOR DEBUGGING
EXTIME:	0			; EXTIME CONTAINS THE NUMBER OF MIX
				; EXECUTE CYCLES SINCE OPERATION
				; BEGAN

MC0000:	BLOCK	=4000		; SIMULATED MIX WORDS

PDL:	BLOCK	40		; PUSH-DOWN LIST

	XALL			;DON'T PRINT TEXT OF MACRO EXPANSIONS
DEFINE ULIST1 {DONEIT←←0}	;*RES* prepare to turn off listing
DEFINE ULIST2 {IFE DONEIT, {DONEIT←←1↔XLIST}}  ;*RES* turn it off
;	The two macros above are used to control length of macro
;	generated code listing.  They are used in the following way:
;
;	ULIST2 is put in a suitable place in the definition of <macro>
;
;	ULIST1
;	<macro>
;	LIST

	SUBTTL	MIXLOG - LOG OF ADDITIONS AND CORRECTIONS

COMMENT ⊗ Log of Additions and Corrections by Dick Sweet to MIX Software 
--------------------------------------------------------------

Early in the game:

All		Much grand old pseudo-opery to control listing size.
MIX000	p. 2	The macros ULIST1 and ULIST2 used above.
MIXIO	p. 4	Literal for cr-ff corrected to 6430
MIXIO	p. 4	Call to PRNWRD in IOC instr
MIXMON	p. 8	Save F in MOD instr, needed by TRACE
MIXMON	p. 11	Re-pick up F in MOVE instr
MIXMON	p. 11	Inserted PATCH area
MIXAL0	p. 15	Fix SCANA1 to work if fewer than 5 chars after ALF
		 N.B. at least 1 is still needed (tab or blank)
MIXBUG	p. 14	Check left half of entry for special case
MIXBUG	p. 14	Put out proper field for IO instr in $E

1/31/72

MIXBUT	p. 1	Put in switches for no eject on printer
MIXBUT	p. 2	Put in code for above switches
MIXIO	p. 3	Put in code for above switches in print routine
MIXBUT	p. 1	Switch for listing news file
MIXBUT	p. 2	Code for above switch
MIX999	p. 2	Call to news routine at initialization
MIX999	p. 3	News routine

2/1/72

All		Started converting files to TVEDIT, page numbers above
		will probably no longer be correct
MIXAL0	p. 18	Martin Frost changed SIXMIX entry for "+" to 44
MIXFIL		Created file from half of first page of MIXIO so that the
		same routine could be used by MIX and MIXAL
MIXFIL	p. 2	Made about 5 corrections to get PPN's processed correctly
MIXIO	p. 6	Changed GETWRD to ignore nulls since INCRD didn't read SOS
		files correctly
MIXAL0.0	Removed FINFO to MIXFIL, inserted ULIST macros

2/3/72

MIXDD		A new file, routines to display machine status on Data Disk
		consoles similar to III routines put in by Dave Barstow
MIXDPY		Changes to make MIXDD work easier.  Notably, replace UPGMVM
		instrs by MOVEM and doing a UPGIOT every time.  Thus, the
		correct values can be picked up out of the III buffer.
MIXBUT		A new button to rewrite DD screen (<ctrl><form>)
MIX999	p. 3	Check for both kinds of DPY at init
MIX999	p. 3	Change # of glitches in piece of paper (3 for III, 4 for DD)
MIX999	p. 3	Initialize PC to MIX 0 (=MC0000) so initial display of PC
		is no longer garbage
MIX999	p. 4	Ask if news desired, first giving user creation date and time
		of the NEWS file.  Consider using MIX.MSG[2,2] some time for
	 	the news file.

2/4/72

MIXMON	p. 9	Removed parens from last 2 entries in M0XCT so that ENTi and
		ENNi wouldn't get an ILL MEM REF when they have an efective
		address of 0 and an index of 6!
MIXBUG	p. 15	Fixed bug that caused program to loop when examining a location
		with a negative address field.
MIXBUG		Several changes to allow various routines to be used by the
		symbolic instruction part of MIXDD
MIXDD	p. 3	Whole new routine to display next instruction in symbolic form.
		It should probably be in MIXDPY and come out on both DD and
		III displays.
MIXERR	P. 2	Fixed error routines to:
			1. Display PC of error
			2. Optionally halt on non-fatal errors
			3. Adjust PC on fatal errors to offending instruction
MIXBUT		New buttons ERRHALT and ERRGO to control action at non-fatal
		errors.

2/7/72

MIX999	p. 3	Initialize PC before calling DDUPD first time now that symbolic
		instr is displayed.
MIXBUT	p. 3	Corrected SKIP instr in QREWRT so that DD displays could be
		rewritten.
MIXBUG	p. 11	Changed GETSYM so that if no match, offset is set to value
MIXDD	p. 3	Various fixes to symbolic display routines

2/8/72

MIXBUT	P. 5	RESCN routine to rescan last TTY line looking for second argument
MIXBUT	p. 4	Use RESCN in SETUP and SETPC routines
MIXFIL	p. 2	Alternate entry for use with RESCN
MIXIO	p. 2	Use RESCN in READ, PUNCH, and PRINT routines
MIXAL0	p. 28	Use RESCN in MIXAL routine
MIXRUN	p. 2	Use RESCN in TRACE and TK routines
MIXMLD	p. 2	Use RESCN in MLD routine

2/9/72

MIXBUT	p. 5	Changed RESCN to just continue reading current line
MIXBUT	p. 2	Changed BUTTON routine to do different things with buttons that
		could have arguments

2/22/72

MIXDD	p. 3	Maximum offset for printing changed from ∞ to 77
MIXDD	p. 5	Moved screen down so EX TIME won't remain on screen
MIXBUT	p. 3	Changed DISPLAY button to do more reasonable things
MIXBUT	p. 4	Fixed initialization of reg 11 in SETPC button
MIXRUN	p. 2	Fixed initialization of reg 10 in TK button

2/23/72

MIXIO	p. 2	Fixed READ, PUNCH and PRINT buttons to read rest of line in
		case file is already open

2/28/72

MIXBUT	p. 5	Fixed RESCN to do the right thing if it starts out with a LF
		as in the case of the TK button
MIXRUN	p. 4	Temporarily put in octal dump for MJH
MIXBUT	p. 2	"	    "	 "  "	  "     "  "

3/10/72

MIXRUN	p. 3	Completely changed TRACE routine (DORUN) to put out values
		in bytewise fashion instead of as 30 bit integers.  In the
		process, did away with Dave's cute "split up the selected
		field" routine to print the contents of the addressed cell.
		It would not be difficult now to allow different formats
		for recording register values in the trace.
MIXRUN	p. 4	Changed DUMP routine to allow dump ranges and variable formats
		for the dumped locations.
MIXRUN	p. 5	Routines for range request and variable format output used
		in the two above changes.  One can specify a "mask" by which
		the value is to be printed.  A mask specifies byte groupings
		and whether the group is to be printed or ignored. e.g. the
		mask "2(1)11" would cause the (bytewise) number "-102030405"
		to be printed as "- 0660405".
MIXBUT	p. 4	Changed dump routine (QDUMP) to the following syntax:
			DUMP {<range>}{<format>}
		Where
			<range>::= <number> | <number>:<number>
			<format>::= /I | /B | /D | /<mask>
			<mask>::= <term> | <mask><term>
			<term>::= <visible field> | <invisible field>
			<visible field>::= <number>
			<invisible field>::= (<number>)
		In the range specification, any number > 3999 is considered
		to be 3999.  In a field specification, the number must be
		between 1 and 5.  The sum of the field sizes must not
		exceed 5.   The Instruction, Byte, and Decimal formats
		correspond to the following masks:
			/I ≡ /2111
			/B ≡ /11111
			/D ≡ /5
MIXMON	p. 2	Changed things so that TRACE shows the register status before
		the instruction is executed.  This necessitated calling GETM
		before going to the instruction routine.
MIXMON		Changed all other GETM instructions to MOVE 12,MSPEC
MIXIO		Changed all GETM instructions to MOVE 12,MSPEC

3/17/72

MIXIO		Noticed that data files created by TV are not read correctly
		apparently the first couple of chars of the line are dropped
		(a reasonable thing to happen).  The problem has not been
		thoroughly diagnosed or fixed at this time.

2/9/75	REG	Combined several source files to eliminate lengthy command lines
		Redefined FINFO as a label, rather than an opdef.
MIXAL1		Down-arrowed definition of P. (formerly file MIXAL0.0)

⊗
	SUBTTL	MIXDPY	- III manipulations

COMMENT	⊗	This page contains the dpy picture apparatus.
	⊗

XMAX ←←	777
XMIN ←←	-777
YMAX ←← 600
YMIN ←← -200

WIDTH ←← =60
HEIGHT ←← =90
BTWEEN ←← =40

DPYHED:	DPYPIC
	ENDAD-.

DEFINE	LVW	(X,Y,M,T)
{	X1 ←←	(X)⊗31 ∧ 3777B10
	Y1 ←←	(Y)⊗16 ∧ 3777B21
	X1 ∨ Y1 ∨ M⊗6 ∨ T⊗4 ∨ 6
}

DEFINE	LVWBS	(X,Y,M,T,B,S)
{	X1 ←←	(X)⊗31 ∧ 3777B10
	Y1 ←←	(Y)⊗16 ∧ 3777B21
	X1 ∨ Y1 ∨ B⊗11 ∨ S⊗8 ∨ M⊗6 ∨ T⊗4 ∨ 6
}

DEFINE	RETURN	(N)
{	LVW	N*-=12,-30,0,2
}

DEFINE	DPYREG
	{ASCID	/+ 00 00 00 00 00    /
}
DEFINE  DPHREG
	{ASCID	/+ 000000 0000       /
}
DEFINE	DPYDAT
	{ASCID	/000000000000   /
}
DEFINE	DPYAD
	{ASCID	/0000 /
}
DEFINE DD1 &(A) {↓DDLB&A:}
DEFINE DD2 &(A) {↓DDSZ&A←←.-DDLB&A}

DPYPIC:	0
	LVW	XMIN,YMAX,1,2
	LVW	XMAX,YMAX,1,0
	LVW	XMAX,YMIN,1,0
	LVW	XMIN,YMIN,1,0
	LVW	XMIN,YMAX,1,0

	LVW	BTWEEN,-BTWEEN-HEIGHT,0,2
	LVW	0,HEIGHT,0,0
	LVW	WIDTH/2,-HEIGHT/2,0,0
	LVW	WIDTH/2,HEIGHT/2,0,0
	LVW	0,-HEIGHT,0,0

	LVW	BTWEEN,0,0,2
	LVW	0,HEIGHT,0,0

	LVW	BTWEEN,-HEIGHT,0,2
	LVW	WIDTH,HEIGHT,0,0
	LVW	-WIDTH,0,0,2
	LVW	WIDTH,-HEIGHT,0,0

	LVW	XMAX-4*BTWEEN-3*WIDTH,YMAX-BTWEEN-HEIGHT,1,2
	LVW	0,HEIGHT,0,0

	LVW	BTWEEN,0,0,2
	LVW	WIDTH,0,0,0
	LVW	0,-HEIGHT,0,0
	LVW	-WIDTH,0,0,0
	LVW	0,HEIGHT,0,0

	LVW	WIDTH+BTWEEN,0,0,2
	LVW	WIDTH,0,0,0
	LVW	0,-HEIGHT,0,0
	LVW	-WIDTH,0,0,0
	LVW	0,HEIGHT,0,0

	LVW	WIDTH+BTWEEN,0,0,2
	LVW	WIDTH,0,0,0
	LVW	0,-HEIGHT,0,0
	LVW	-WIDTH,0,0,0
	LVW	WIDTH,HEIGHT/2,0,2
	LVW	-WIDTH,0,0,0
	LVW	0,HEIGHT/2,0,0

	LVW    	XMIN+BTWEEN,250,1,2

DD1(12)
	ASCID	/rA : /
DPYRA:	DPYREG
DD2(12)
	RETURN	=25

DD1(13)
	ASCID	/rX : /
DPYRX:	DPYREG
DD2(13)
	RETURN	=25

DD1(14)
	ASCID	/ri1: /
DPYRI1:	DPHREG
DD2(14)
	RETURN	=25

DD1(15)
	ASCID	/ri2: /
DPYRI2:	DPHREG
DD2(15)
	RETURN	=25

DD1(16)
	ASCID	/ri3: /
DPYRI3:	DPHREG
DD2(16)
	RETURN	=25

DD1(17)
	ASCID	/ri4: /
DPYRI4:	DPHREG
DD2(17)
	RETURN	=25

DD1(20)
	ASCID	/ri5: /
DPYRI5:	DPHREG
DD2(20)
	RETURN	=25
DD1(21)
	ASCID	/ri6: /
DPYRI6:	DPHREG
DD2(21)
	RETURN	=25

DD1(11)
	ASCID	/rJ : /
DPYRJ:	DPHREG
DD2(11)

	LVW	0,250,1,2

DD1(1)
	ASCID	/EXECUTE TIME = /
DPYXT:	DPYREG
DD2(1)
	RETURN	=35

DD1(2)
	ASCID	/PROGRAM COUNTER   = /
DPYPC:	DPYAD
DD2(2)
	RETURN	=25

DD1(3)
	ASCID	/INS: /
DPYIN:	DPYREG
DD2(3)
	RETURN	=25

	RETURN	0

DD1(5)
DPYOV:	ASCID	/     OVERFLOW  /
DD2(5)
	RETURN	=15
	RETURN	0

DD1(6)
DPYG:	ASCID	/     GREATER   /
DD2(6)
	RETURN	=15

DD1(7)
DPYE:	ASCID	/   → EQUAL/
DD2(7)
	RETURN	=10

DD1(10)
DPYL:	ASCID	/     LESS /
DD2(10)


ENDAD:	XWD	DPYPIC, 20
COMMENT	⊗	This section has all the display facilities, including
		all the handy-dandy, neat little pictures.
	⊗

UPDAD:	0

OPDEF	UPDATE	[PUSHJ  P, .]
	SKIPE	DDSW		;ARE WE ON A DD?
	JRST	.+5		;YES
	MOVNI	10, 1
	GETLIN	10
	SKIPL	10
	POPJ	P,
INDS:	MOVE	10, DPYOFF
	TLNE	FLAGS, OVFLAG
	MOVE	10, DPYON
	MOVEM	10, DPYOV
	MOVE	10, DPYOFF
	TLNE	FLAGS, GFLAG
	MOVE	10, DPYON
	MOVEM	10, DPYG
	MOVE	10, DPYOFF
	TLNE	FLAGS, EFLAG
	MOVE	10, DPYON
	MOVEM	10, DPYE
	MOVE	10, DPYOFF
	TLNE	FLAGS, LFLAG
	MOVE	10, DPYON
	MOVEM	10, DPYL
REGS:	MOVEI	10, REGLST			; INIT ADDRESS COUNTER
	MOVEM	10, UPDAD
	SKIPN	10, @UPDAD			; 0 → NO MORE
	JRST	DATS
	MOVE	10, (10)			; 10 ← SOURCE WORD
	MOVE	12, [POINT  7, REGBLK]		; POINTER TO DESTINATION BLOCK
	MOVE	13, [POINT  3, 10, 5]		; POINTER TO SOURCE
	MOVEI	11, "+"				; FIRST DO SIGN BIT
	SKIPGE	10
	ADDI	11, 2				; CHANGE TO "-"
	IDPB	11, 12
	IBP	12				; SPACE
	ILDB	11, 13				; FIRST DIGIT OF PAIR
	ADDI	11, 60
	IDPB	11, 12
	ILDB	11, 13				; SECOND DIGIT OF PAIR
	ADDI	11, 60
	IDPB	11, 12
	TLNE	13, 770000			; ANY MORE PAIRS?
	JRST	.-10				; YES
	HLRZ	10, @UPDAD			; PREPARE FOR TRANSFER TO DPY AREA
	MOVE	11, REGBLK
	MOVEM	11, (10)			; NOW DO TRANSFER
	AOJ	10,
	MOVE	11, REGBLK+1
	MOVEM	11, (10)
	AOJ	10,
	MOVE	11, REGBLK+2
	MOVEM	11, (10)
	AOJ	10,
	MOVE	11, REGBLK+3
	MOVEM	11, (10)
	AOS	UPDAD				; GET NEXT REGISTER
	JRST	REGS+2
DATS:	MOVEI	10, DATLST			; INIT ADDRESS COUNTER
	MOVEM	10, UPDAD
	SKIPN	10, @UPDAD			; 0 → NO MORE
	JRST	ADS
	MOVE	10, (10)			; 10 ← SOURCE WORD
	MOVE	12, [POINT  7, DATBLK]		; POINTER TO DESTINATION BLOCK
	MOVE	13, [POINT  3, 10]		; POINTER TO SOURCE
	ILDB	11, 13
	ADDI	11, 60
	IDPB	11, 12
	TLNE	13, 770000			; ANY MORE PAIRS?
	JRST	.-4				; YES
	HLRZ	10, @UPDAD			; PREPARE FOR TRANSFER TO DPY AREA
	MOVE	11, DATBLK
	MOVEM	11, (10)			; NOW DO TRANSFER
	AOJ	10,
	MOVE	11, DATBLK+1
	MOVEM	11, (10)
	AOJ	10,
	MOVE	11, DATBLK+2
	MOVEM	11, (10)
	AOS	UPDAD				; GET NEXT REGISTER
	JRST	DATS+2
ADS:	MOVEI	11, ADLST			; INIT ADDRESS COUNTER
	MOVEM	11, UPDAD
	SKIPN	11, @UPDAD
	JRST	BYTES
	HRRZ	12, (11)			; 12 ← SOURCE WORD
	SUBI	12, MC0000
	MOVE	13, [POINT  7, ADBLK]		; POINTER TO DESTINATION BLOCK
	MOVEI	10, =1000			; 10 WILL HOLD DIVISOR
	MOVE	11, 12				; SET UP FOR DIVIDE
	IDIV	11, 10				; GET DIGIT
	ADDI	11, 60
	IDPB	11, 13
	IDIVI	10, =10				; FIX DIVISOR
	JUMPG	10, .-5
	HLRZ	10, @UPDAD			; PREPARE FOR TRANSFER TO DYP AREA
	MOVE	11, ADBLK
	MOVEM	11, (10)			; NOW DO TRANSFER
	AOS	UPDAD				; GET NEXT REGISTER
	JRST	ADS+2
BYTES:	MOVEI	10, BYTLST			; INIT ADDRESS COUNTER
	MOVEM	10, UPDAD
	SKIPN	10, @UPDAD			; 0 → NO MORE
	JRST	DPYOUT				;GO WRITE SCREEN (III OR DD)
	HRRZ	11, @UPDAD			; UPMEM ← SOURCE ADDRESS
	MOVEM	11, UPMEM
	MOVEI	13, BYTDES-BYTLST		; UPBYTE ← GROUP DESCRIPTOR
	ADD	13, UPDAD
	MOVE	12, (13)
	MOVEM	12, UPBYTE
	MOVNI	12, 4				; UPBTIM ← COUNTER FOR GROUP #
	MOVEM	12, UPBTIM
	MOVE	13, [XWD  DPYMDL, DPYWRK]	; SET UP WORK AREA
	BLT	13, DPYWRK-DPYMDL+DPYWRK-1
	MOVE	13, [POINT  7, DPYWRK]		; AND POINTER
	MOVEM	13, UPOINT
	MOVEI	13, "+"				; GET SIGN
	SKIPGE	@UPMEM
	MOVEI	13, "-"
	IDPB	13, UPOINT
	IBP	UPOINT
NXTGRP:	MOVE	13, UPBYTE			; 13 ← 5*n+i
	IMULI	13, 5
	ADD	13, UPBTIM
	SKIPN	DPYPTR+4(13)
	JRST	ALLDON				; 0 → ALL DONE
	LDB	12, DPYPTR+4(13)		; GET BYTE GROUP
	MOVE	10, DPYDIV+4(13)		; 10 ← DIVISOR
	MOVE	11, 12
	IDIV	11, 10
	ADDI	11, 60
	IDPB	11, UPOINT			; PUT DIGIT INTO WORK AREA
	IDIVI	10, =10				; NEXT DIVISOR
	JUMPG	10, .-5				; BACK FOR MORE DIGITS
	IBP	UPOINT				; SPACE AFTER GROUP
	AOSG	UPBTIM				; MORE GROUPS?
	JRST	NXTGRP				; YES
ALLDON:	MOVEI	13, 3
	HLRZ	10, @UPDAD
	HRRM	10, .+2
	MOVE	11, DPYWRK(13)
	MOVEM	11, 0(13)
	SOJGE	13, .-2
	AOS	UPDAD
	JRST	BYTES+2


DPYOUT:	SKIPE	DDSW		;IS THIS A DATA DISK
	JRST	DDUPD		;YES, UPDATE SCREEN (DDUPD DOES A POPJ)
	UPGIOT	DPYHED		;REWRITE III SCREEN
	POPJ	P,




DPYOFF:	ASCID	/     /
DPYON:	ASCID	/   → /

REGLST:	0
REGBLK:	DPYREG

DATLST:	0
DATBLK:	DPYDAT

ADLST:	XWD	DPYPC, PC
	0
ADBLK:	DPYAD

BYTLST:	XWD	DPYIN, INSTR
	XWD	DPYRA, RA
	XWD	DPYRX, RX
	XWD	DPYRI1, R1
	XWD	DPYRI2, R2
	XWD	DPYRI3, R3
	XWD	DPYRI4, R4
	XWD	DPYRI5, R5
	XWD	DPYRI6, R6
	XWD	DPYRJ, RJ
	XWD	DPYXT, EXTIME
	0
BYTDES:	7
	17
	17
	2
	2
	2
	2
	2
	2
	2
	0
	0
UPMEM:	0
UPBTIM:	0
UPOINT:	0
UPBYTE:	0
DPYMDL:	ASCID	/                    /
DPYWRK:	ASCID	/                    /



QUPDAT:	MOVNI	10, 1				; IS IT A DPY
	GETLIN	10
	JUMPGE	10, .+3				; NO → DON'T UPDATE
	PGSEL	0				; PICK PIECE OF GLASS
	UPDATE
	JRST	BUTTON

COMMENT	⊗	If the PDP address of the word to be displayed is
		in UPMEM then the following tables can be used to
		get the appropriate byte groups for updating the
		display.

			n = a 4-bit number, where bit k is on if
				byte k in the MIX word should begin
				a new grouping.  (e.g.  standard
				instruction format is:
					n=7   or   + AA I F C)

			i = the # of the group which you wish to use (1≤i≤5)

			DPYPTR+5*n+i-1   is a byte pointer to the right bytes
					 or 0 if no bytes left

			DPYDIv+5*n+i-1   contains the divisor to start finding
					 the digits with
	⊗


ULIST1
DPYPTR:	FOR I←0,17
 {ULIST2
  X1←←X2←←X3←←X4←←X5←←6
  Y1←←=11
  Y2←←=17
  Y3←←=23
  Y4←←=29
  Y5←←=35
  Z←←1


  FOR @$ J←3,0,-1
   {IFE I∧1⊗J,
     {FOR @! K←Z,Z
       {X!K←←X!K+6
        Y!K←←Y!K+6
       }
      FOR @! K←Z+1,4
       {FOR @% K1←K+1,K+1
         {X!K←←X%K1
          Y!K←←Y%K1
         }
       }
     }
    IFN I∧1⊗J,	{Z←←Z+1}
   }


  FOR @$ J←1,Z
   {	POINT  X$J, @UPMEM, Y$J
   }
  FOR J←Z+1,5
   {	0
   }
 }
LIST

ULIST1
DPYDIV:	FOR I←0,17
 {ULIST2
  X1←←X2←←X3←←X4←←X5←←6
  Z←←1


  FOR @$ J←3,0,-1
   {IFE I∧1⊗J,
     {FOR @! K←Z,Z
       {X!K←←X!K+6
       }
      FOR @! K←Z+1,4
       {FOR @% K1←K+1,K+1
         {X!K←←X%K1
         }
       }
     }
    IFN I∧1⊗J,	{Z←←Z+1}
   }


  FOR @$ J←1,5
   {D←←1
    FOR K←1,X$J/3-1
     {D←←=10*D
     }
	D
   }
 }
LIST
	SUBTTL	MIXDD	DD manipulation routines

COMMENT ⊗ ROUTINES TO DISPLAY MIX STATUS ON DATA DISK DISPLAYS

	For each screen entry, there is a shadow entry kept of the
contents of the screen.  When DDUPD is called, only those things which
have changed are rewritten.  
⊗
BEGIN DDDPY
	T←←	0
	A←←	1
	B←←	2
	C←←	3
	D←←	4
	E←←	5
	F←←	6
	NEWMSK←←  16


↑DDUPD:			;UPDATE DD DISPLAY
	MOVEM	16,SVREG+16	;SAVE REGISTERS
	MOVEI	16,SVREG
	BLT	16,SVREG+15

; Update DD screen ***
spec←15
tac7←←7
tac6←←6
tac5←←5
tac4←←4
tac1←←1
tac2←←2
t←←0
value←←10
	movei	tac7,lintbl	; First ldb
	move	tac1,upd0
	movem	tac1,upd1
	movei	tac1,topbuf
	movem	tac1,buftop	; Start at the beginning of the buffer
updlp:	skipn	tac5,linmod(tac7)	; zero mode means empty line
	 jrst	nxtupd			; Go on to next line
	hrrz	value,linadr(tac7)	; MIX adr of cell
	trne	tac5,4000		; was this a register ?
	 addi	value,svreg-acsave	; since we save registers in a different
					; place than MIXBUG does.
	pushj	p,fetch			; get contents
	camn	tac6,linval(tac7)	; match ?
	 jrst	nxtupd			; yes, so don't need to touch this line
	pushj	p,setlb			; set up label again
					; [future mod: add space in each ldb for
					;  the label, saving lots of time.]
	ldb	tac5,[point 4,linmod(tac7),35]	; get back the mode
	push	p,tac7			; save list pointer
	pushj	p,@modes(tac5)		; call appropriate display routine
	pop	p,tac7			; restore pointer
	pushj	p,endlin
nxtupd:	hlrz	tac7,linadr(tac7)	; get next link
	caie	tac7,lintbl		; all the way around ?
	 jrst	updlp			; no so do next line
	move	tac1,buftop		; get top of buffer
	camn	tac1,topbuf		; did any lines change ?
	 popj	p,			; no, so don't touch the screen !
	setzm	(tac1)			; make a "halt" DD instruction
	subi	tac1,ddbuf-1		; length of buffer
	movem	tac1,ddopg+1
	upgiot	ddopg			; *** write out screen ***
	jrst	writ4			; restore acs and leave





NXS2:	MOVEI	A," "
	IDPB	A,T		;DEPOSIT 2 BLANKS
	IDPB	A,T

;	DO THE OP CODE

	MOVE	7,10		;GET REL LOC OF INSTR
	PUSHJ	P,DECIDF	;DECIDE ABOUT F FIELD
	MOVE	B,@STROP(10)	;GET OP CODE MNEMONIC
	MOVEM	B,MNEM#
	MOVE	B,[POINT 7,MNEM]
	ILDB	A,B
	JUMPE	A,NXS3		;COPY UNTIL 0
	IDPB	A,T
	JRST	.-3
NXS3:	MOVEI	A," "		;NOW 2 MORE BLANKS
	IDPB	A,T
	IDPB	A,T

;	DO THE ADDRESS PART

	HLRZ	10,MC0000(7)	;PICK UP ADDR OF INSTR
	SKIPL	MC0000(7)	;IS IT NEGATIVE
	JRST	NXS5		;NO
	ANDI	10,7777
	TLO	10,400000	;TURN ON SIGN BIT
	PUSHJ	P,GETNSM	;LOOK UP IN SYMTAB
	JUMPN	4,NXS4		;EXACT MATCH
	MOVEI	A,"-"		;WE'LL NEED THIS IN ANY OTHER CASE
	IDPB	A,T
	JUMPN	3,NXS4		;THERE WAS A ABS VAL MATCH
	HRRZ	4,10		;PUT ABS VAL IN OFFSET SLOT
	JRST	NXS6		;GO DO IT
NXS4:	PUSHJ	P,SYMOUT	;PUT OUT SYMBOLIC
	JRST	NXS7
NXS5:	PUSHJ	P,SYMGET	;LOOK UP SYMBOL AND OFFSET
	JUMPE	3,NXS6		;NO SYMBOL
	SKIPN	3(3)		;SEE IF VALUE OF SYMBOL IS 0
	JRST	NXS6		;DO LIKE RAID, DON'T PRINT IT
	CAIG	4,77		;DON'T PUT OUT AN OFFSET OF GREATER THAN 77
	JRST	.+3
	MOVE	4,10		;PUT VALUE OF LOC IN REG 4
	JRST	NXS6		;PUT THAT VALUE IS DISPLAY
	PUSHJ	P,SYMOUT	;WRITE SYMBOL
	JUMPE	4,NXS7		;NO OFFSET
	MOVEI	A,"+"
	IDPB	A,T		;PUT OUT A +
NXS6:	PUSHJ	P,NUMOUT	;PUT OUT OFFSET

;	DO INDEX FIELD

NXS7:	LDB	4,[POINT 6,MC0000(7),23]	;PICK UP INDEX
	JUMPE	4,NXS8		;NO INDEX
	MOVEI	A,","
	IDPB	A,T		;PUT OUT A ,
	PUSHJ	P,NUMOUT	;PUT OUT INDEX VALUE

;	DO F FIELD IF NOT THE DEFAULT FOR THE OP CODE

NXS8:	;JUMPN	6,UPD1		;GO UPDATE
	MOVEI	A,"("
	IDPB	A,T
	LDB	4,[POINT 6,MC0000(7),29]	;GET FIELD SPEC
	PUSHJ	P,NUMOUT	;WRITE IT OUT
	MOVEI	A,")"
	IDPB	A,T
;	JRST	UPD1		;NOW GO WRITE SCREEN

COMMENT ⊗ WRITE OUT THE LABEL WHICH IS A SIXBIT STRING OF UP TO 12 CHARACTERS
	IN LOCATIONS 1(3)-2(3).  DEPOSIT ASCII CHARACTERS BY POINTER T
	⊗
symout:	move	a,1(3)
	movem	a,symb
	move	a,2(3)
	movem	a,symb+1
	move	b,[point 6,symb]
	ILDB	A,B		;GET A CHAR
	JUMPE	A,cpopj		;QUIT AT 0
	ADDI	A,40		;CONVERT TO ASCII
	IDPB	A,T		;STORE IN OUTPUT BUFFER
	JRST	.-4
symb:	block	3

COMMENT ⊗ WRITE OUT THE NUMBER IN REG 4 IN DECIMAL ⊗

↑↑NUMOUT:IDIVI	4,=10		;DIVIDE BY TEN
	HRLM	5,(P)		;SAVE ON STACK
	SKIPE	4		;IS THAT ALL
	PUSHJ	P,NUMOUT	;NO
	HLRZ	4,(P)		;GET DIGIT OFF STACK
	ADDI	4,60		;CONVERT TO ASCII
	IDPB	4,T		;STORE IT
cpopj:	POPJ	P,		;NEXT DIGIT OR RETURN

↑↑symprt:pUSHJ	P,SYMGET	;GET LABEL FOR INSTR
	JUMPE	3,NXS1		;NO SYMBOL
	SKIPN	3(3)		;SEE IF VALUE OF SYMBOL IS 0
	JRST	NXS1		;DO LIKE RAID, DON'T PRINT IT
	CAIG	4,77		;DON'T PUT OUT AN OFFSET OF GREATER THAN 77
	JRST	.+3
	MOVE	4,10		;PUT VALUE OF LOC IN REG 4
	JRST	NXS1		;PUT THAT VALUE IS DISPLAY
	PUSHJ	P,SYMOUT	;PUT SYMBOL IN BUFFER
	JUMPE	4,cpopj		;NO OFFSET
	MOVEI	A,"+"
	IDPB	A,T		;DEPOSIT A +
nxs1:	jrst	numout
; Subroutine to see if a line needs to be updated
; enter with 	tac5: mode code
;		tac6: MIX word we want displayed
;		value: address of this word (relative to mc0000)
; exits with T = a byte pointer to deposit stuff into & label set up,
;	or jumps to bugout if no changes need to be made


↑↑setl: move	tac7,curtop
setla:	hrrz	tac4,linadr(tac7)	; Same address ?
	came	tac4,value
	 jrst	setla1			; No--try next line
	camn	tac6,linval(tac7)	; Values match ?
	came	tac5,linmod(tac7)	; and modes ?
	 jrst	setlb			; nope
	pop	p,(p)			; yes, so forget it.
	jrst	bugout
setla1:	hlrz	tac7,linadr(tac7)	; get next link
	came	tac7,curtop		; come all the way around ?
	 jrst 	setla			; no--go check next line
	hrrm	value,linadr(tac7)
setlb:	movem	tac6,linval(tac7)	; update the ldb
	movem	tac5,linmod(tac7)
	move	t,buftop		; set up the byte pointer
	move	tac1,linins(tac7)
	movem	tac1,@t			; put in DD instruction
	aoj	t,
	hrli	t,440700		; make bp
	movei	tac1,40			; first two positions are blank
	idpb	tac1,t
	idpb	tac1,t			; for future expansion(eg *s a la RAID?)
	trnn	tac5,4000		; Is this a register ?
	 jrst	setlc			; no.
	lsh	tac5,-4
	andi	tac5,177		; get ascii for register name
	movei	tac1,"r"		; print cute stuff
	idpb	tac1,t
	movei	tac1,"I"		; is it an index register ?
	caig	tac5,"9"
	 idpb	tac1,t			; yes
	idpb	tac5,t
	jrst	.+2
setlc:	pushj	p,symprt		; stuff in label
	movei	tac5,40
	move	tac2,buftop
	addi	tac2,3
	hrli	tac2,010700		; last char of buftop+3
	idpb	tac5,t			; fill out 4 word's worth
	came	t,tac2
	 jrst	.-2
	hlrz	tac5,linadr(tac7)	; get adr of next ldb
	movem	tac5,curtop		; which is where next line may go
	popj	p,


; Subroutine to set up odd numbered entry in ddbuf
↑↑setbuf:hrrz	tac1,t
	sub	tac1,buftop		; this is the length of the latest entry
	movni	tac2,-1(tac1)		; make aobjn pointer
	hrl	tac2,tac2
	hrr	tac2,buftop
	movei	tac4,1
	orm	tac4,1(tac2)		; convert text to DD text
	aobjn	tac2,.-1
	movs	tac2,buftop		; start of latest entry
	hrr	tac2,t			; top of buffer space
	addi	tac1,-1(tac2)		; last word transfered goes here
	blt	tac2,(tac1)		; copy latest entry
	hrri	t,1(tac1)		; new top of buffer space
	hrrzm	t,buftop
	movei	tac1,10000
	orm	tac1,(tac2)		; turn into odd numbered line adr
	popj	p,
COMMENT ⊗ NOW WRITE ALL INFO TO THE DATA DISK BUFFER ⊗

;PD1:	MOVNI	A,NDPY		;GET # OF ENTRIES
	SKIPA	NEWMSK,[0]	;ZERO OUT MASK FOR CHANGED ENTRIES
LKDPY:	LSH	NEWMSK,1	;GET PLACE FOR BIT FOR NEXT ENTRY
	MOVE	B,SIZE+NDPY(A)	;GET (SIZE OF ENTRY)-1
	HLRZ	C,LOC+NDPY(A)	;GET LOC OF NEW ENTRY
	HRRZ	D,LOC+NDPY(A)	;GET LOC OF SHADOW ENTRY
	HRLI	C,B
	HRLI	D,B

;	Now compare entry with shadow entry

CMPR:	MOVE	T,@C		;PICK UP WORD OF NEW
	CAME	T,@D		;COMPARE TO SHADOW
	JRST	NEW1		;NOT THE SAME
	SOJGE	B,CMPR		;LOOK AT NEXT WORD
	AOJLE	A,LKDPY		;NO CHANGE IN ENTRY, LOOK AT NEXT ENTRY
	JRST	WRIT1		;THAT'S ALL, GO WRITE EVEN LINES
NEW1:	IORI	NEWMSK,1	;TURN ON BIT IN MASK
	AOJLE	A,LKDPY		;LOOK AT NEXT ENTRY

;	At this point, NEWMSK has a bit on for each entry that has changed
;	from what it is on the screen.  Write even lines of these entries


WRIT1:
	JUMPE	NEWMSK,WRIT4	;QUIT IT THERE'S NOTHING TO DO
	MOVEM	NEWMSK,MSKSAV#	;SAVE MASK
	MOVEI	A,NDPY		;GET # OF ENTRIES
	MOVEI	E,DDBUF+1	;POINT TO DD BUFFER
	SKIPA
WRIT1A:	LSH	NEWMSK,-1	;GET BIT FOR NEXT ENTRY
	JUMPE	NEWMSK,WRIT2	;QUIT IF NO MORE HAVE CHANGED
	TRNN	NEWMSK,1	;IS BIT ON FOR THIS ENTRY?
	SOJA	A,WRIT1A	;NO
	MOVE	T,DDCODE(A)	;GET DD INSTR
	MOVEM	T,(E)		;STORE IN BUFFER
	MOVEI	B,1(E)		;GET LOC OF AVAIL BUFFER
	MOVE	C,B		;SAVE LOC
	HLL	B,LOC(A)	;GET LOC OF NEW ENTRY
	ADD	C,SIZE(A)	;POINT TO LAST LOC OF BLT
	BLT	B,(C)		;MOVE NEW ENTRY TO BUFFER
	ADD	E,SIZE(A)
	MOVE	T,CRLF		;TACK CR-LF ON END OF ENTRY
	MOVEM	T,2(E)
	ADDI	E,3		;MOVE E PAST NEW CODE
	SOJGE	A,WRIT1A	;NOW DO NEXT ENTRY

;	Now write odd lines and move entries to shadows

WRIT2:
	MOVE	NEWMSK,MSKSAV	;GET MASK
	MOVEI	A,NDPY		;GET # OF ENTRIES
	SKIPA
WRIT2A:	LSH	NEWMSK,-1	;GET BIT FOR NEXT ENTRY
	JUMPE	NEWMSK,WRIT3	;QUIT IF NO MORE HAVE CHANGED
 	TRNN	NEWMSK,1	;IS BIT ON FOR THIS ENTRY?
	SOJA	A,WRIT2A	;NO
	MOVE	T,DDCODE(A)	;GET DD INSTR
	IORI	T,10000		;SPECIFY ODD LINE
	MOVEM	T,(E)		;STORE IN BUFFER
	MOVEI	B,1(E)		;GET LOC OF AVAIL BUFFER
	MOVE	C,B		;SAVE LOC
	HLL	B,LOC(A)	;GET LOC OF NEW ENTRY
	ADD	C,SIZE(A)	;POINT TO LAST LOC OF BLT
	BLT	B,(C)		;MOVE NEW ENTRY TO BUFFER
	ADD	E,SIZE(A)
	MOVE	T,CRLF		;TACK CR-LF ON END OF ENTRY
	MOVEM	T,2(E)
	ADDI	E,3		;MOVE E PAST NEW CODE
	MOVE	B,LOC(A)	;NOW MOVE TO SHADOW
	MOVEI	C,(B)
	ADD	C,SIZE(A)
	BLT	B,(C)
	SOJGE	A,WRIT2A	;NOW DO NEXT ENTRY

;	We are now ready to write the buffer

WRIT3:
	SETZM	T,(E)		;PUT A 0 AT THE END OF THE BUFFER
	SUBI	E,DDBUF-1	;CALCULATE SIZE OF BUFFER
	MOVEM	E,DDOPG+1
	UPGIOT	1,DDOPG		;WRITE SCREEN

;	The display is updated, restore registers and return

WRIT4:	MOVSI	16,SVREG
	BLT	16,16
	POPJ	P,

SVREG:	BLOCK	17		;REGISTERS SAVED HERE
↑↑DDOPG:DDBUF
	0
↑↑CRLF: ASCID	/
/
COMMENT ⊗ TABLES USED BY DDUPD ⊗
DD1(4)
	ASCID	/NEXT INS: /		;BUFFER FOR SYMBOLIC NEXT INSTRUCTION
NXINS:	BLOCK	12
DD2(4)

NDPY←←21-1

SIZE:		;CONTAINS (SIZE OF ENTRY)-1

	FOR @& A←NDPY+1,1,-1
{DDSZ&A -1
}

MAXBUF←←0	;COUNTER TO DETERMINE BUFFER SIZE NEEDED
MAXSHA←←0	;POINTER INTO SHADOW TABLE

LOC:		;CONTAINS XWD <LOC OF ENTRY>,<LOC OF SHADOW>

	FOR @& A←NDPY+1,1,-1

{	XWD	DDLB&A,SHADOW+MAXSHA
MAXSHA←←MAXSHA+DDSZ&A
MAXBUF←←MAXBUF+DDSZ&A+2
}

A←←344

DDCODE:		;CONTAINS DATA DISK INSTRUCTION FOR ENTRY

	REPEAT NDPY+1, {BYTE (8) 2,A⊗-4,A∧17 (3) 3,4,5,4
		A←←A-14}

SHADOW:	BLOCK	MAXSHA+1

↑↑DDBUF:BYTE	(8) 46,2,2 (3) 1,3,3,4
↑↑topbuf:BLOCK	2*MAXBUF+2

↑↑curtop:lintbl
↑↑buftop:topbuf

lin←←60		; first line reserved for (gasp) error messages, etc.
↑↑lintbl:
repeat =15,{
	block	2
	xwd	.+2,-1
	byte	(8) 2,lin⊗-4,lin∧17 (3) 3,4,5,4
lin←←lin+14}
	block	2
	xwd	lintbl,-1	; circular list of ldbs
	byte	(8) 2,lin⊗-4,lin∧17 (3) 3,4,5,4

linmod←←0	; bits 0-24: byte mask if any
		; bits 25-36 output mode
linval←←1	; last known value
linadr←←2	; LH: link to next ldb,, RH: adr of this cell rel to mc0000
linins←←3	; DD display instruction for positioning this line

; DD instruction to position display to first line for messages.
define ddflin {byte (8) 2,44⊗-4,44∧17 (3) 3,4,5,4}
COMMENT ⊗ ROUTINE TO REFRESH WHOLE SCREEN ⊗

↑REWRIT:	;REWRITE WHOLE SCREEN
	MOVEM	0,SVREG		;SAVE REGISTER 0
	SETZM	SHADOW		;ZERO OUT SHADOW REGISTERS
	MOVE	0,[XWD SHADOW,SHADOW+1]
	BLT	0,SHADOW+MAXSHA
	MOVE	0,SVREG
	JRST	DDUPD		;UPDATE SCREEN

BEND DDDPY
	SUBTTL	MIXBUT	Handle "console buttons"

COMMENT	⊗	This section requests the user to "push a button" and
		then acts on that request.
	⊗

↓BUTTON:
	pushj	p,ddupd		; III users can forget it!!!
	OUTSTR	[ASCIZ ⊗
#⊗] 						; PROMPT FOR BUTTON
	MOVE	13, [POINT  7, 10]		; INITIALIZE BYTE POINTER
	INCHWL	11				; WAIT FOR LINE
	ANDI	11,177				;*RES* IGNORE CONTROL BITS
	CAIN	11,14				;*RES* IS THIS A FORM FEED
	JRST	QREWRT				;*RES* YES, REWRITE DD SCREEN
	cain	11, 175				; is it an <alt-mode>
	jrst	mixbug				; yes → go to the debugger
	SKIPA	10, [0]				; CLEAR 10 AND SKIP
BUT0:	INCHRW	11				; GE NEXT CHAR
	CAIL	11, "a"				; convert lower to upper
	CAILE	11, "z"
	SKIPA
	SUBI	11, 40
	CAIN	11,40				;*RES* IS IT A BLANK
	JRST	.+6				;*RES* YES
	CAIN	11, 15				; C-R → END OF BUTTON
	JRST	.+4
	IDPB	11, 13				; PUT CHAR INTO 10
	TLNE	13, 760000			; P=1 → 10 IS FULL
	JRST	BUT0
	MOVE	11, BLIST
	CAMe	10, BLIST(11)			; THIS BUTTON?
	AOBJN	11, .-1				; NO → IF BUTTONS LEFT, TRY THEM
	jumpge	11,BUT1				;*RES* TRY BUTTONS WITH ARGUMENTS
	INCHRW	10				; WAIT FOR L-F
	CAIE	10, 12
	JRST	.-2
	JRST	@ALIST(11)
BUT1:	MOVE	11,BLIST1			;*RES* GET POINTER TO BUTTON LIST
	CAMe	10,BLIST1(11)
	AOBJN	11,.-1
	jumpl	11,@alist1(11)
	OUTSTR	[ASCIZ /??/]			; FUNNY BUTTON
	clrbfi
	JRST	BUTTON

BLIST:	XWD	-ALIST+BLIST+1, 1
	0
	ASCII	⊗G⊗
	ASCII	⊗GO⊗
	ASCII	⊗S⊗
	ASCII	⊗START⊗
	ASCII	⊗L⊗
	ASCII	⊗LOAD⊗
	ASCII	⊗C⊗
	ASCII	⊗CONT⊗
	ASCII	⊗H⊗
	ASCII	⊗HALT⊗
	ASCII	⊗STEP⊗
	ASCII	⊗X⊗
	ASCII	⊗D⊗
	ASCII	⊗DISP⊗
	ASCII	⊗M⊗
	ASCII	⊗MEM⊗
	ASCII	⊗ZXT⊗
	ASCII	⊗ZPC⊗
	ASCII	⊗EXIT⊗
	ASCII	⊗READX⊗
	ASCII	⊗PNCHX⊗
	ASCII	⊗PRNTX⊗
	ASCII	⊗UPDAT⊗
	ASCII	⊗PCMLD⊗
	ASCII	⊗TRACX⊗
	ASCII	⊗NOEJE⊗		;*RES*
	ASCII	⊗EJECT⊗ 	;*RES*
	ASCII	⊗NEWS⊗		;*RES*
	ASCII	⊗ERRHA⊗		;*RES*
	ASCII	⊗ERRGO⊗		;*RES*
	ASCII	⊗MJH⊗
	ASCII	⊗DUM1⊗		;*RES* IN CASE NEEDED FOR PATCH
	ASCII	⊗DUM2⊗
ALIST:	0
	BUTTON+1
	QGO
	QGO
	QSTART
	QSTART
	QLOAD
	QLOAD
	QCONT
	QCONT
	QHALT
	QHALT
	QSTEP
	QSTEP
	QDISP
	QDISP
	QMEM
	QMEM
	QZXT
	QZPC
	QEXIT
	QREADX
	QPNCHX
	QPRNTX
	QUPDAT
	QPCMLD
	QRUNX
	QNOEJ			;*RES*
	QEJEC			;*RES*
	QNEW			;*RES*
	QERHLT			;*RES*
	QERRGO			;*RES*
	QMJH
	QDUM
	QDUM

BLIST1:	XWD	-ALIST1+BLIST1+1,1
	ASCII	⊗READ⊗
	ASCII	⊗PUNCH⊗
	ASCII	⊗PRINT⊗
	ASCII	⊗SETUP⊗
	ASCII	⊗MIXLO⊗
	ASCII	⊗MLD⊗
	ASCII	⊗TRACE⊗
	ASCII	⊗TK⊗
	ASCII	⊗SETPC⊗
	ASCII	⊗MIXAL⊗
	ASCII	⊗DUMP⊗
	ASCII	⊗DUM3⊗
	ASCII	⊗DUM4⊗
ALIST1:	0
	QREAD
	QPUNCH
	QPRINT
	QSETUP
	QMLD
	QMLD
	QRUN
	QRUNC
	QSETPC
	MIXAL
	QDUMP
	QDUM
	QDUM

QSTART:	SETZB	RJ, EXTIME			; EXTIME, RJ ← 0
	MOVEI	PC, MC0000			; PC ← MC0000
	JRST	MIXMN1

QGO:	MOVEI	INSTR, 2044			; THIS IS  "IN 0(16)"
	MOVEI	PC, MC0000			; SET PC TO ZERO
	JRST	MIXMN2				; NOW EXECUTE THE "IN"

QLOAD:	MOVEI	INSTR, 2044			; THIS IS  "IN 0(16)"
	TLO	FLAGS, SIFLAG			; SET THE SINGLE-INSTRUCTION FLAG
	JRST	MIXMN2				; NOW EXECUTE THE "IN"


QCONT:	JRST	MIXMN1				; GO RIGHT TO WORK

QHALT:	JRST	BUTTON				; ESSENTIALLY A NO-OP

QSTEP:	TLO	FLAGS, SIFLAG			; SET SIFLAG
	JRST	MIXMN1

QZXT:	SETZM	EXTIME				; EXTIME ← 0
	JRST	BUTTON

QZPC:	SETZ	RJ,				; RJ ← 0
	MOVEI	PC, MC0000			; PC ← MC0000
	JRST	BUTTON

QNOEJ:	SETOM	NOJECT				;*RES* WRITE OVER PERF ON
	JRST	BUTTON				;*RES*       LPT

QEJEC:	SETZM	NOJECT				;*RES*
	JRST	BUTTON				;*RES*
NOJECT:	0

QERHLT:	SETOM	ERRHLT				;*RES* HALT ON NON-FATAL ERRORS
	JRST	BUTTON

QERRGO:	SETzM	ERRHLT				;*RES* CONTINUE ON NON-FATAL ERRS
	JRST	BUTTON

QREWRT:	SKIPE	DDSW				;*RES* IS THIS A DATA DISK
	PUSHJ	P,REWRIT			;*RES* YES, REWRITE SCREEN
	JRST	BUTTON

QNEW:	PUSHJ	P,QNEWS				;*RES* WRITE OUT CURRENT NEWS
	JRST	BUTTON

QMJH:	SETOM	MJHSW#				;OCTAL DUMPS FOR JO
	JRST	BUTTON

QDUM:	JRST	BUTTON				;*RES* DUMMY SWITCHES ARE NO-OPS

QEXIT:	CALL	[SIXBIT  /EXIT/]		; SO LONG UNTIL TOMORROW

QMEM:	OUTSTR	[ASCIZ ⊗ADDRESS ⊗]
	INCHRW	11
	CAIN	11, "X"
	JRST	BUTTON
	ANDI	11, 17
	IMULI	11, =1000
	MOVE	10, 11
	INCHRW	11
	ANDI	11, 17
	IMULI	11, =100
	ADD	10, 11
	INCHRW	11
	ANDI	11, 17
	IMULI	11, =10
	ADD	10, 11
	INCHRW	11
	ANDI	11, 17
	ADD	10, 11
	OUTCHR	[":"]
	MOVE	10, MC0000(10)
	PUSHJ	P, PMIX
	JRST	QMEM

QDISP:	OUTSTR	[ASCIZ ⊗

DISPLAY:
⊗]
	OUTSTR	[ASCIZ ⊗  EXTIME=⊗]
	MOVE	10, EXTIME
	PUSHJ	P, OUTD1		;*RES*
	OUTSTR	[ASCIZ ⊗
  PC    =⊗]
	MOVEI	10,-MC0000(PC)		;*RES*
	PUSHJ	P, OUTD1		;*RES*
	OUTSTR	[ASCIZ ⊗
  RA    =⊗]
	MOVE	10, RA
	PUSHJ	P, PMIX
	OUTSTR	[ASCIZ ⊗  RX    =⊗]
	MOVE	10, RX
	PUSHJ	P, PMIX
	OUTSTR	[ASCIZ ⊗  RJ    =⊗]
	MOVE	10, RJ
	PUSHJ	P, OUTD1		;*RES*
	JRST	BUTTON

POCT:	MOVE	13, [POINT  3, 10]
	ILDB	11, 13
	ADDI	11, 60
	OUTCHR	11
	TLNE	13, 770000
	JRST	.-4
	OUTSTR	[ASCIZ ⊗
⊗]
	POPJ	P,

PMIX:	MOVEI	11, 53
	SKIPGE	10
	ADDI	11, 2
	OUTCHR	11
	MOVE	13, [POINT  3, 10, 5]
	OUTCHR	[" "]
	ILDB	11, 13
	ADDI	11, 60
	OUTCHR	11
	ILDB	11, 13
	ADDI	11, 60
	OUTCHR	11
	TLNE	13, 770000
	JRST	.-10
	OUTSTR	[ASCIZ ⊗
⊗]
	POPJ	P,

QSETUP:	SETZ	10,
	PUSHJ	P,RESCN			;*RES* LOOK FOR A SECOND ARG
	MOVE	11,RECHAR		;*RES* FOUND ONE
	JRST	.+5			;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ /INSTRUCTIONS BETWEEN DISPLAY UPDATES: /]
	INCHWL	11
	SKIPA
	INCHRW	11
	CAIN	11, 15
	JRST	.+5
	ANDI	11, 17
	IMULI	10, =10
	ADD	10, 11
	JRST	.-6
	MOVEM	10, UPD0
	INCHRW	10
	CAIE	10, 12
	JRST	.-2
	JRST	BUTTON

QDUMP:	SKIPN	RUNC
	JRST	BUTTON
	PUSHJ	P,RANGE			;*RES* DETERMINE DUMP RANGE
	movei	11,			; zap default
	CAIE	10,"/"			;*RES* IS A MODE SPECIFIED?
	JRST	QDMP1A			;NO
	INCHWL	10
	CAIN	10,"I"			;INSTRUCTION MODE?
	MOVE	11,IMASK
	CAIN	10,"B"			;BYTE MODE?
	MOVE	11,BMASK
	CAIN	10,"D"			;DECIMAL MODE?
	MOVE	11,DMASK
	JUMPN	11,QDMP1
	PUSHJ	P,MSPARS		;GET SPECIAL MASK
	MOVE	11,MASK
	CAIG	13,5			;IS MASK SIZE OKAY
	JRST	QDMP1			;YES
	OUTSTR	[ASCIZ /DUMP MASK IS MORE THAT 5 BYTES LONG
/]
	JRST	QBUTN
QDMP1A:	MOVE	11,BMASK		; Default mode is 5 bytes
QDMP1:	MOVEM	11,DFALTM		;STORE DEFAULT MASK
	SKIPA
	INCHWL	10
	CAIE	10,12
	JRST	.-2
	JRST	DUMP			;GO TO THE DUMP

QSETPC:	PUSHJ	P,RESCN			;*RES* LOOK FOR A SECOND ARG
	MOVE	10,RECHAR		;*RES* FOUND ONE
	JRST	.+3			;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ ⊗NEW VALUE FOR P.C. = ⊗]
	INCHWL	10
	SKIPA	11, [0]
QSPC1:	INCHRW	10
	CAIN	10, 15
	JRST	QSPC2
	IMULI	11, =10
	SUBI	10, 60
	ADD	11, 10
	JRST	QSPC1
QSPC2:	INCHRW	10
	ADDI	11, MC0000
	MOVE	PC, 11
	JRST	BUTTON

COMMENT ⊗ RESCN routine to scan the rest of the line of TTY input looking an
	argument.  Call is PUSHJ P,RESCN.  On return, the first character of
	the second argument is in location RECHAR and subsequent TTY inputs 
	will get the other characters.  If there is no second argument on the 
	line,the routine skips 2 instructions on return.
	⊗

RESCN:
	PUSH	P,10			;SAVE REGISTER
RESCN1:	INCHRW	10			;READ A CHAR
	CAIN	10,15
	JRST	RESCN2
	CAIN	10,12			;MAYBE A LF
	JRST	RESCN3			;YES, GET OUT OF HERE
	CAIN	10,40			;SKIP OVER ANY BLANKS
	JRST	RESCN1

;	We have read to a non-blank, non-CR character

	MOVEM	10,RECHAR		;SAVE THE CHARACTER
	POP	P,10
	POPJ	P,			;RETURN

;	We found a CR before finding a second argument

RESCN2:	INCHRW	10
	CAIE	10,12			;READ LF ALSO
	JRST	.-2
RESCN3:	MOVEI	10,2			;SET TO SKIP 2 ON RETURN
	ADDM	10,-1(P)
	POP	P,10			;RESTORE REGISTER
	POPJ	P,

RECHAR:	0

BEGIN	MIXBUG ↔ SUBTTL MIXBUG - Dynamic debugger for MIX machine

COMMENT	⊗
	MIXBUG is the dynamic debugger that goes with MIX.  It is essentially
	a few more buttons.  Each of these buttons has <alt-mode> as
	the first character of its name.  The buttons are as follows:
		$B address	This sets a breakpoint at address.
		$U address	This removes the breakpoint at address
		$U		This removes all breakpoints
		$E address	This examines and dipslays the contents of address
				in symbolic instruction mode.
		$ES address	This examines the contents of address in symbolic
				decimal mode.
		$EB address	This examines the contents of address in byte mode.
		$EA address	This examines the contents of address in ALF mode.
		$ED address	This examines the contents of address in decimal
				mode.
		$EN address	This examines the contents of address in numeric-
				instruction mode.
		$=S address	This evaluates the address and types it (the address
				itself) in symbolic form.
		$=D address	This evaluates the address and types it in decimal
				form.
		$DW address← w-value		This deposits this w-value in this
						address.
		$DI address← instruction	This deposits this instruction in
						this address.
		$J address	This begins execution at this address
		$X instruction	This causes this instruction to be executed.
		$<line-feed>	This causes *+1 to be displayed in the same mode
				as *

		Note:	all addresses, instructions, w-values may be
			symbolic, using the symbols of the most recently
			loaded .MLD file.  The special character *
			when not used as a multiply operator, means
			the address of the currently open location,
			if there is one, and the value of the P.C.
			if there is no currently open location.

	⊗

t←0
tac1←1
tac2←2
tac3←3
tac4←4
tac5←5
tac6←6
tac7←7
value←10
v1←11
scant←12
scnval←13
char←14
spec←←15
spec2←←16

↑acsave: block	17		; for saving the ac's
numsym:	0			; 0 if still possibly a number
seqnam:	0			; will hold the sequence name at various times
	0
origin:	-1			; will hold the value of *

comment	⊗	INCHAR is a subroutine to read one char from the TTY and
		convert it to sixbit.  the char is returned in the acc. CHAR.
		if a <c-r> is read, the following <l-f> is also read and
		returned as octal 100.
	⊗

opdef	inchar	[pushj p, .]
inchr0:	inchwl	char			; read a char
	SETZM	METAF
	SETZM	CTRLF
	TRZE	CHAR,200		; Set control and meta flags appropriately
	 SETOM	CTRLF
	TRZE	CHAR,400
	 SETOM	METAF
	jumpe	char, INCHR0		; ignore <null>
	cain	char, 11		; convert <tab>
	movei	char, " "		; to <space>
	cain	char, 15		; ignore <c-r>
	 jrst	inchr0
	cain	char, 12		; convert <l-f>
	 jrst	[movei	char, 100	; to octal 100
		popj	p,]		; and return
	trze	char, 100		; convert other chars to sixbit
	troa	char, 40
	trz	char, 40
	popj	p,			; return

CTRLF:	0
METAF:	0
comment	⊗	SCAN is a subroutine to return one input token.  the token
		is returned in SCANT, its associated value (if it has one)
		is returned in SCNVAL, and the first char of the next token
		is in CHAR.
		the permissable tokens are given below:
	⊗

LINE←0		; end of line
COMMA←1		; comma
LPAREN←2	; left-parenthesis
RPAREN←3	; right-parenthesis
SYM←4		; identifier or number (associated value is the MIX word for the right thing)
PLUS←5		; plus
MINUS←6		; minus
STAR←7		; asterisk (associated value is value of ORIGIN)
SLASH←10	; slash
DOWNAR←11	; double slash
COLON←12	; colon
WHAT←13		; identifier not found in symbol table
LEFTAR←14	; left arrow
SPACE←15	; space or other delimiter
reg←16		; αR followed by one of {a,1,2,3,4,5,6,x,j} means appropriate register

OP:	0	; GETS SET IF CURRENT TOKEN IS A LEGAL MIX OP (OPCODE → V1).
comment	⊗	CHRTAB gives information about the various input chars:
		  CHRTAB+i=	0    if it is an illegal character
				k    if k is the token number for it and it isn't special
			 bits ∨ k    if k is the sixbit for the token and bits are special bits:
					bit 0 → a letter or a digit
					bit 1 → a letter
					bit 2 → a LINE or a SLASH
	⊗

ULIST1
CHRTAB:	for i ← 0,100
{ULIST2
 	j←←0
	ife i-100,	{j←← 1b2 ∨ line}
	ife i-' ',	{j←← space}
	ife i-',',	{j←← comma}
	ife i-'(',	{j←← lparen}
	ife i-')',	{j←← rparen}
	ife i-'+',	{j←← plus}
	ife i-'-',	{j←← minus}
	ife i-'*',	{j←← star}
	ife i-':',	{j←← colon}
	ife i-'←',	{j←← leftar}
	ife i-'/',	{j←← 1b2 ∨ slash}
	ifge i-'A',	{ifle i-'Z',	{j←← 3b1 ∨ i-20}}
	ifge i-'0',	{ifle i-'9',	{j←← 1b0 ∨ i-20}}
	j
}
LIST
opdef	scan	[pushj p, .]
scan00:	jumpn	char, .+3		; wait for non-blank character
	inchar
	JUMPE	CHAR,.-1		; IGNORE SPACES
	SETZM	OP			; NOT AN OP (YET).
	move	scnval, origin		; default value of scnval is ORIGIN
	SKIPE	CTRLF			; CONTROL CHARS ARE SPECIAL
	 JRST	SCAN4
	skipn	scant, chrtab(char)	; check table
	jrst	bugerr			; illegal character
	tlnn	scant, 700000		; are any of the special bits on
	jrst	inchr0			; no → put next char in CHAR
	tlze	scant, 100000		; is it LINE or SLASH?
	jrst	[caie	scant, slash	; yes, is it slash?
		popj	p,		; no → it's line, so return
		inchar			; get next char
		caie	char, '/'	; is next char a slash?
		popj	p,		; no → return
		movei	scant, downar	; and compress two slashes into downar
		jrst	inchr0]		; and finally, return
	move	tac1, [point 6, seqnam]	; pointer to sequence name
	setzm	seqnam			; set sequence name to blanks
	setzm	seqnam+1
	movei	tac2, =12		; maximum of 12 chars
	setzb	scnval, numsym		; scnval starts as zero, numsym shows number
scan1:	tlze	scant, 200000		; is it a letter
	setom	numsym			; yes → we don't have a number
	tlz	scant, 400000		; turn off letter-digit bit
	sosl	tac2			; one more char in seqnam
	idpb	char, tac1		; so put it there
	imuli	scnval, =10		; no fix up scnval if number
	add	scnval, scant
	inchar				; get next char
	skipn	scant, chrtab(char)	; and look at table
	jrst	bugerr			; illegal character
	jumpl	scant, scan1		; if it's a digit or letter, keep the sequence going
	movei	scant, sym		; not a digit or letter, so we have whole sequence
	skipn	numsym			; was it a number?
	popj	p,			; yes → return with right token and value
	ldb	tac1, [point 8, seqnam, 7]	; hash into symbol table
	ldb	tac2, [point 8, seqnam, 15]	; by taking first two groups of 8 bits
	xor	tac1, tac2		; and XORing them
	addi	tac1, symtab		; this gives us the actual pointer
	skipa				; for the first time through
scan2:	hrrz	tac1, (tac1)		; get base address of next entry
	jumpe	tac1,	[movei	scant, what	; zero → this symbol is not in the table
			jrst	scan5]		; LOOK & SEE IF IT'S A MIX OP
	move	tac2, seqnam		; see if this entry is it
	came	tac2, (tac1) 1		; do first six chars match?
	jrst	scan2			; no → try next entry
	move	tac2, seqnam+1		; now try next six chars
	came	tac2, (tac1) 2		; do they match?
	jrst	scan2			; no → try next entry
	move	scnval, (tac1) 3	; yes → this is it so get associated MIX word
scan3:	movei	scant, sym		; it's a symbol

;SEE IF THE TOKEN IS A VALID MIX OP. IF SO, PUT THE OP CODE IN V1 AND
;SET OP FLAG.
scan5:	skipe	seqnam+1		; second part of sequence name blank ?
	popj	p,			; nope; it can't be an op.

	movei	tac4, oplist		; no we will find op-code by a binary search
	movei	tac5, lastop		; tac4 and tac5 contain the lower and upper bounds
inst1:	move	tac1, tac5		; get index
	add	tac1, tac4
	lsh	tac1, -1		; divide by two to get average
	move	tac2, (1)		; get OP for comparison
	sub	tac2, seqnam
	jumpg	tac2, lower		; it is lower on the list
	jumpl	tac2, upper		; it is higher on the list
	move	v1, gotop-oplist (tac1)
	SETOM	OP			; SET OP FLAG
	popj	p,

lower:	movni	tac5, 1			; reset upper limit
	addb	tac5, tac1		;	to index-1
lwr1:	caml	tac5, tac4		; lower>upper → error
	jrst	inst1
	popj	p,			; it wasn't an op; just return

upper:	movei	tac4, 1			; reset lower limit
	addb	tac4, tac1		;	to index+1
	jrst	lwr1

; control characters come here
scan4:	caie	char,'r'
	 popj	p,
	pushj	p,inchr0		; get another char
	movei	scnval,=9
	move	tac2,[point 6,[sixbit/jx654321a/]]
	ildb	tac1,tac2
	came	tac1,char
	 sojg	scnval,.-2
	jumple	scnval,bugerr		; funny register name
	addi	tac1,40			; convert to ascii again
	movem	tac1,regnm		; and save for output routines
	addi	scnval,acsave-mc0000-1
	cain	scnval,acsave-mc0000+=9-1
	 movei	scnval,acsave-mc0000+rj	;for some obscure reason rj isn't 
					;consequtive with the others.
	movei	scant,reg
	jrst	inchr0
↑↑regnm:0
repeat	0,<
regnum:	acsave-mc0000+ra	; give addresses in acsave relative to mc0000
	acsave-mc0000+r1
	acsave-mc0000+r2
	acsave-mc0000+r3
	acsave-mc0000+r4
	acsave-mc0000+r5
	acsave-mc0000+r6
	acsave-mc0000+rx
	acsave-mc0000+rj>; end of repeat 0,
comment	⊗	EXPR is a subroutine to read in and evaluate an expression.
		it assumes that the first char of the first token is in CHAR.
		it skips on return if a valid expression was found--VALUE
		contains the MIX word generated by the expression.
		it doesn't skip if a valid expression was not found.
		in either case, the next token is in SCANT.
	⊗


opdef	expr	[pushj p, .]
expr00:	scan				; get first token
expr0a:	setzb	value, spec		; we initialize value to zero
	cain	scant, reg		; if it is a reg
	soja	spec,[move	value,scnval
		 scan			; get next token to stay in synch
		 jrst	cpopj]		; return
expr01:	caie	scant, sym		; if it is SYM
	cain	scant, star		; or *
	jrst	[move	value, scnval	; we start off
		jrst	expr2]
	caie	scant, plus		; if it is +
	cain	scant, minus		; of -
	jrst	expr1			; yes → we have a unary-operator
cpopj1:	aos	(p)			; otherwise it is a valid exprssion (empty)
cpopj:	popj	p,			; so skip on return

expr1:	move	tac3,scant		; save operator
	scan				; get next token
	cain	scant, sym		; is it a symbol
	jrst	.+3			; yes → we're OK
	caie	scant, star		; or a *
	popj	p,			; no → error
	cain	tac3, minus		; was operator a minus sign?
	tlc	scnval, 400000		; yes → complement sign bit of MIX word
	move	value, scnval		; value is now what we want it to be

expr2:	scan				; get next token
	cail	scant, plus		; is it a binary-operator
	caile	scant, colon
	 jrst	cpopj1			; no → we have found our expression
	move	tac3, scant		; remember what the operator is

expr3:	scan				; get next token
	cain	scant, sym		; is it a symbol
	jrst	.+3			; yes → we're OK
	caie	scant, star		; or *
	popj	p,			; no → error return
	move	tac4, value		; save original value
	tlze	value, 400000		; convert value to two's complement
	movns	value
	tlze	scnval, 400000		; convert scnval to two's complement
	movns	scnval
	xct	binop-plus(tac3)	; do whatever the operation calls for
	jumpg	value, expr2		; value less than 0 → it's already in MIX format
	jumpe	value,	[tlne	tac4, 400000	; value=0 → must check sign of first operand
			tlo	value, 400000	; first operand < 0 → new value should be also
			jrst	expr2]	; now we have MIX format
	movns	value			; value less than 0 → take negative
	tlo	value, 400000		; and turn on sign bit
	jrst	expr2			; and go back for next operator

binop:	add	value, scnval		; PLUS → we add the operands
	sub	value, scnval		; MINUS → we subtract the operands
	imul	value, scnval		; STAR → we multiply the operands
	idiv	value, scnval		; SLASH → we divide the operands
	pushj	p,	[setz	value+1	; DOWNAR → special divide
			ashc	value, -5
			div	value, scnval
			popj	p,]
	pushj	p,	[imuli	value, =8	; COLON → usually for fields
			add	value, scnval
			popj	p,]
comment	⊗	WVAL is a subroutine to read in and evaluate a w-value.
		it assumes that the first char of the first token is in CHAR.
		it skips on return if a valid w-value was found--VALUE
		contains the MIX word generated by the w-value.
		it doesn't skip if a valid w-value was not found.
		in either case, the next token is in SCANT.
	⊗

opdef	wval	[pushj p, .]
wval00:	setzb	tac7,spec		; tac7 will hold w-value while it is being generated
	SCAN				; GET FIRST TOKEN
	SKIPE	OP			; IS IT A MIX OP?
	 JUMPE	CHAR,WVAL4		;  YES, BUT IGNORE UNLESS FOLLOWED BY SPACE
	PUSHJ	P,EXPR0A
	jrst [	jumpe	spec,wval2a	; not a register so null expr
		popj	p,]
	JRST	WVAL1A
WVAL1:	expr				; get an expression
	 JRST	WVAL2A			; COULDN'T SO ALL DONE
wval1a:	movei	tac6, 5			; tac6 will hold the f-part
	move	tac3, value		; save value of expression
	cain	scant, lparen		; is it a left-paren?
	jrst	wval3			; yes → go get f-part

wval2:	caile	tac6, 5			; does f-part include sign bit?
	jrst	.+4			; no
	JUMPGE	tac3,.+2		; yes → test sign of operand
	tloa	tac7, 400000		; and use it
	tlz	tac7, 400000
	MOVE	TAC6, fpoint(tac6)	; now get other bytes
	TDC	TAC6,[12,,MC0000≠7]
	DPB	TAC3,TAC6
	cain	scant, comma		; comma?
	jrst	wval1			; yes → back for next part
WVAL2A:	move	value, tac7		; put proper thing into value
	JRST	CPOPJ1			; so skip on return

sv3:	0
wval3:	movem	tac3,sv3		; expr wipes out tac3
	expr				; get expression for f-part
	popj	p,			; couldn't → error in w-value
	move	tac6, value		; need to remember value of f-part
	caie	scant, rparen		; is it right-paren?
	popj	p,			; no → error in w-value
	skipl	tac6			; is it a valid f-part?
	caile	tac6, 55		; first test: is it in the right range?
	popj	p,			; no → error
	skipn	fpoint(tac6)		; is table entry zero?
	popj	p,			; yes → error
	scan				; get next token after )
	move	tac3,sv3		; restore tac3
	jrst	wval2			; scan again

; HERE WHEN WE CHANCE UPON A MIX OPCODE FOLLOWED BY A SPACE
; PARSE THE INSTRUCTION.
WVAL4:	MOVE	TAC7,V1			; V1 has the opcode
	expr				; get expression for address
	jrst	bugerr			; error
	trz	value, 770000		; get rid of bad bits
	hrl	tac7, value		; put address into assembling MIX word
	skipge	value			; was sign bit on?
	tlo	tac7, 400000		; yes → turn it on here, too
	caie	scant, comma		; is next token a comma?
	jrst	inst3			; no → then we don't have an index field
	expr				; get expression for the index field
	jrst	bugerr			; error
	dpb	value, [point 6, tac7, 23]	; put index field into MIX rd

inst3:	caie	scant, lparen		; is next token a left-parenthesis
	jrst	inst4			; no → then we don't have a field-field
	expr				; expression for field
	jrst	bugerr			; error
	caie	scant, rparen		; next token should be right-paren
	jrst	bugerr			; it ain't
	dpb	value, [point 6, tac7, 29]	; put field into MIX word
	scan				; must get next token after )

inst4:	jumpn	scant, bugerr		; final token should be LINE
	move	value, tac7		; this is the assembled instruction
	jrst	cpopj1			; give good return
comment	⊗	FPOINT is a table of byte pointers for depositing things
		into tac7.  if an entry is zero, then it is not a valid f-part.
		the sign byte is not included.
	⊗
REPEAT 0,<
fpoint:	44b5
	for y←1,5
	{point	y*6, tac7, y*6+5
	}
	repeat	2,	{0}
	for x←1,5
	{for y←0,5
	 {ifge y-x, then {point (y-x+1)*6, tac7, y*6+5
			 }
	  ifl y-x, then	 {0
			 }
	 }
	repeat	2,	{0}
	}>; End of repeat 0( this code is duplicated (almost) elsewhere)
comment	⊗	INST is a subroutine to read an instruction.
		the MIX word which is the instruction is returned in
		VALUE.  control is transferred to bugerr if a valid
		instruction is not found.
	⊗
COMMENT + THIS CODE IS NOW ON PAGES 20-2 AND 22 +
comment	⊗	ADDR is a subroutine to read an expression and see whether
		it is a valid address.
		it also checks to see that this is the last token in the line.
	⊗

opdef	addr	[pushj p, .]
addr0:	inchar				; input a char to start the expr
	WVAL				; get the expression
	 jrst [	jumpe	spec,bugerr
		jrst	addr1]		; register names are legal addresses.
	jumpl	value, bugerr		; out of range → error
	caile	value, =3999
	jrst	bugerr
addr1:	movem	value, origin		; save address in ORIGIN
	popj	p,			; return


comment	⊗	ADDRC is a subroutine to read an expression and see whether
		it is a valid address.
		it also checks to see that it is followed by a left-arrow.
	⊗

opdef	addrc	[pushj p, .]
addrc0:	addr				; get a legal address
	caie	scant,leftar		; left arrow ?
	 jrst	bugerr			; no → error
	popj	p,			; return
comment	⊗	GETSYM is a subroutine to find a symbolic expression for
		a value.  only symbols with equivalent MIX words between
		0000 and 3999 are considered.  GETSYM assumes that VALUE
		contains the value to be considered.  a pointer to the
		best symbol table entry is returned in tac3 (zero if no
		symbol was found) and the offset is returned in tac4.
	⊗

opdef	getsym	[pushj p, .]
↑SYMGET:				;*RES* so I can call it from MIXDD
gets0:	setz	tac3,			; we obviously haven't found a symbol yet
	movei	tac4, =4000		; and no symbol could have a worse offset than this
	movei	tac1, linked		; to start table search
gets1:	skipn	(tac1) 1		; is there an entry?
	JRST	GETS3			;*RES* no → search is over
	skipl	tac2, (tac1) 3		; is equivalent value less than zero?
	caile	tac2, =3999		; or greater than 3999?
	jrst	gets2			; yes → not a valid symbol
	sub	tac2, value		; get difference between value and symbl's equivalent
	movns	tac2			; take VALUE-SYMBOL
	jumpl	tac2, gets2		; don't want a negative offset
	caml	tac2, tac4		; is it better than we already have?
	jrst	gets2			; no → then don't use it
	move	tac3, tac1		; yes → then we should save it
	move	tac4, tac2
gets2:	addi	tac1, 4			; now look at next entry
	jrst	gets1
GETS3:	SKIPN	TAC3			;*RES* IF NO HIT,
	MOVE	TAC4,VALUE		;*RES*   SET OFFSET TO VALUE
	POPJ	P,
comment	⊗	these are a couple of subroutines to do some outputting:
			OUTDEC - output a space followed by the decimal number in VALUE
			OUTNAM - output a space followed by the sequence name in VALUE,VALUE+1
	⊗

opdef	outdec	[pushj p, .]
↑outd1:	idivi	value, =10		; get digits from right end
	hrlm	value+1, (p)		; put them on the stack
	skipe	value			; was that the last digit?
	pushj	p, outd1		; no → go back for more
	hlrz	value, (p)		; get digit off stack
	addi	value, 60		; convert to ascii
	idpb	value,t			; output it
	popj	p,			; next digit or return


opdef	outnam	[pushj p, .]
outnm0:	move	tac4, [point 6, value]	; pointer to chars is in tac4
outnm1:	ildb	tac5, tac4		; get a char
	jumpe	tac5, outnm2		; blank → end of sequence
	addi	tac5, 40		; convert to ascii
	idpb	tac5,t			; output the char
	came	tac4, [point 6, value+1, 35]	; was that the 12th char?
	jrst	outnm1			; no
outnm2:	popj	p,			; return
comment	⊗	MIXBUG is the starting address of the command interpreter.
	⊗

↑mixbug:
	movei	p, acsave		; save all ac's except p
	blt	p, acsave+16
	move	p, [iowd 40, pdl]	; initialize push-down-pointer
	skipge	origin			; do we already have an address there?
	jrst	[hrrz	tac1, acsave+pc	; no → then use value of p.c.
		subi	tac1, mc0000	; relative to mc0000
		movem	tac1, origin
		jrst	.+1]
	movei	tac1,topbuf
	movem	tac1,buftop
	inchar				; input the first char
	cain	char, 'E'		; is it an E (sixbit)
	jrst	examin			; yes → go to examine
	cain	char, 'D'		; is it a D?
	jrst	dposit			; yes → go to dposit
	cain	char, 'B'		; is it a B?
	jrst	break			; yes
	cain	char, 'U'		; is it a U?
	jrst	ubreak			; yes
	cain	char, 'J'		; how about J?
	jrst	jumper			; yes
	cain	char, 'X'		; or X?
	jrst	xxxx			; yes
	cain	char, '='		; =?
	jrst	equal			; yes
	cain	char, 100		; line-feed?
	jrst	lf			; yes
					; none of these → error

bugerr:	outstr	[asciz /???
/]
↑↑bugout:jumpe	scant, .+3		; wait for LINE
	scan
	jrst	.-2
	movsi	p, acsave		; restore all ac's
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	jrst	button			; and return to button mode
comment	⊗	EXAMIN is what looks at core locations and displays what it sees.
	⊗

examin:	inchar				; get type of examin
	movei	tac5,6			; 6 legal codes
	move	tac6,[point 6,[sixbit/ndabs /]]
	ildb	tac2,tac6
	came	tac2,char		; match ?
	 sojg	tac5,.-2		; no.
	jumple	tac5,bugerr
	movem	tac5,mode		; save mode
	addr				; pick up address
	push	p,value			; save value
	pushj	p,fetch			; get contents for setl
	exch	value,(p)		; get back original value for setl
	move	tac5,mode		; restore tac5 for setl
	jumpe	spec,ex1		; is ths a register ?
	move	tac2,regnm		; yes, so save reg name for setl
	lsh	tac2,4
	tro	tac2,4000		; and set register code.
	tro	tac5,(tac2)
ex1:	pushj	p,setl			; set up display line pointer
	pop	p,value			; now use new value which may be the address
					; of a breakpoint storage cell.
	move	tac5,mode		; get mode (again)
	pushj	p,@modes(tac5)		; call appropriate output routine
; Finish up the current line and send it to the DD
bugdis:	pushj	p,endlin		; fill out word with spaces & add crlf
	move	tac1,buftop		; top of buffer space
	setzm	1(tac1)			; stick in a "halt"
	subi	tac1,ddbuf-1		; length of entire buffer
	movem	tac1,ddopg+1		; for upgiot uuo
	upgiot	ddopg			; *** write out new line(s) ***
  	jrst	bugout
↑↑endlin:movei	tac1,40
	idpb	tac1,t			; fill with blanks
	camg	t,[300700,,0]		; skip if just deposited in bits 0-6
	 jrst	.-2
endl1:	move	tac1,crlf		; put crlf at end
	movem	tac1,@t
	aoja	t,setbuf		; copy entry for odd #ed raster line
	
mode:	0
↑↑modes:0
	es0
	es00
	eb0
	ea0
	ed00
	en0

; Subroutine to fetch into tac6 the contents of the MIX cell with address
; relative to mc0000 in value.
↑↑fetch:hlro	tac6,mc0000(value)
	aoje	tac6,fetch1		; jumps if it's breakpointed
	move	tac6,mc0000(value)	; just normal.
	popj	p,
fetch1:	hrrz	tac6,mc0000(value)	; get breakpoint table offset
	movei	value,bptab+1-mc0000(tac6); kludge up value to fool display subrs.
	move	tac6,bptab+1(tac6)	; and the instruction we stored.
	popj	p,
; put out cell in symbolic instruction mode
es0:	move	tac7, value		; tac7 will index to location
	movei	tac1,40
	idpb	tac1,t
	PUSHJ	P,DECIDF		;*RES* DECIDE WHETHER TO PRINT F
	JRST	ESI2			;GO DO IT

COMMENT ⊗  The following routine is called to decide whether the F-field of
	the instruction is to be printed.  It is called by PUSHJ P,DECIDF,
	with the relative instruction counter in register 7.  On return, reg
	10 contains the op code, reg 11 contains the field and reg 6 is a
	flag: zero if field is to be printed, non-zero otherwise.  As a nice
	side effect, the op code mnemonic is an ASCIZ string at @STROP(10) on
	exit.
	⊗
↑DECIDF:
	ldb	value, [point 6, mc0000(tac7), 35]	; get op code
	ldb	value+1, [point 6, mc0000(tac7), 29]	; and f-field
	setom	tac6			; tac6 will know whether we should output the field
	hlrz	tac2, strop(value)	;*RES* are there special names for different fields?
	jumpe	tac2, esi1		; no
	cain	value, 5		; is op special?
	jrst	[caile	value+1, 3
		setzb	value+1, tac6
		POPJ	P,]
	cain	value, 6		; or is it a shift?
	jrst	[caile value+1, =8
		setzb	value+1, tac6
		POPJ	P,]
	cain	value, =39		; or is it a jump?
	jrst	[caile	value+1, =12
		setzb	value+1, tac6
		POPJ	P,]
	caige	value, =40		; or one of these jumps?
	jrst	esi1
	caig	value, =47
	jrst	[caile	value+1, =8
		setzb	value+1, tac6
		POPJ	P,]
	caig	value, =55		; or one of the modifies?
	jrst	[caile	value+1, 4
		setzb	value+1, tac6
		POPJ	P,]

esi1:	cain	value, 0		; is it a NOP?
	jrst	[caie	value+1, 0
		setz	tac6,
		POPJ	P,]
	cain	value, 7		; is it a MOVE?
	jrst	[caie	value+1, 1
		setz	tac6,
		POPJ	P,]
	cain	value, =32		; is it STJ?
	jrst	[caie	value+1, 2
		setz	tac6,
		POPJ	P,]
	caige	value, =56		; is it one which has (0:5) as standard field?
	caig	value, =33
	jrst	[caie	value+1, 5
		setz	tac6,
		POPJ	P,]
	jumpe	value+1,.+2		;*RES* otherwise, it uses (0)
	setz	tac6,
	POPJ	P,

stuff5:	hrli	tac1,440700
	movei	tac2,5
	ildb	tac3,tac1
	jumpn	tac3,.+2
	movei	tac3,40
	idpb	tac3,t
	sojg	tac2,.-4
	popj	p,

esi2:	movei	tac1,@strop(value)	; output the op-code
	pushj	p,stuff5
	movei	tac1,40
	idpb	tac1,t
	hlrz	value, mc0000(tac7)	; get address part
	andi	value, 7777		; get good bits
	skipge	mc0000(tac7)		; is it negative?
	tlo	value, 400000		; turn on sign bit
	jumpge	value, esi23
	PUSHJ	P,GETNSM		;*RES* FIND NEG SYMBOL
	JRST	ESI22			;*RES* GO PRNT IT OUT

COMMENT ⊗  The following routine finds whether a negative address is in the 
	symbol table in either its negative form or absolute value.  It is
	called by PUSHJ P,GETNSM with the relative address reg 10.  On return,
	if there was a match in either case, register 3 contains the symbol
	table address.  If there was an exact match, reg 4 is non-zero.
	Reg 11 is destroyed.
	⊗

↑GETNSM:
	hrrz	value+1, value		; value+1 has absolute value
	setzb	tac3, tac4		; we will search for a match
	movei	tac1, linked		; of value or |value|
esi21:	skipn	(tac1) 1		; is there an entry?
	POPJ	P,			;*RES* no → end of table
	camn	value, (tac1) 3		; is this a match?
	jrst	[move	tac3, tac1	; yes → we will use it
		setom	tac4		; to remember it was exact
		POPJ	P,]		;*RES*
	camn	value+1, (tac1) 3	; match of absolute value?
	move	tac3, tac1		; yes → remember it
	ADDI	TAC1,4			;*RES* POINT TO NEXT ENTRY
	jrst	esi21			; and back to table

esi22:	jumpn	tac4, esi221		; -1 → exact match
	movei	tac1,"-"
	idpb	tac1,t
	jumpn	tac3, esi221		;*RES* tac3=0 → no suitable symbol found
	HRRZ	VALUE,VALUE		;*RES* GET ABSOLUTE VALUE
	JRST	ESI24			;*RES* GO WRITE IT
esi221:	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
	jrst	esi3			; all done with address field

esi23:	getsym				; get a matching symbol
	jumpe	tac3, esi24		; no match
	caile	tac4, =100		; maximum offset of 100
	jrst	esi24
	move	tac2, tac4		; remember offset
	move	value, (tac3) 1		; output name
	move	value+1, (tac3) 2
	outnam
	move	value, tac2		; now do the offset
	jumpe	value, esi3		; zero → don't type it
	movei	tac1,"+"
	idpb	tac1,t
esi24:	outdec				; this could be any of several values

esi3:	ldb	value, [point 6, mc0000(tac7), 23]	; get index field
	jumpe	value, esi4		; zero → don't output it
	movei	tac1,","
	idpb	tac1,t
	getsym				; get a matching symbol
	jumpn	tac4,	[outdec		; not an exact match, so don't use it
			jrst	esi4]
	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
esi4:	jumpn	tac6, esi5		; are we supposed to output the field-field?
	movei	tac1,"("
	idpb	tac1,t
	ldb	value, [point 6, mc0000(tac7), 29]	; get it
	getsym				; get a matching symbol
	jumpn	tac4,	[outdec		; not an exact match, so don't use it
			jrst	esi41]
	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
esi41:	movei	tac1,")"
	idpb	tac1,t

esi5:	popj	p,
eb0:	movei	tac1, "+"		; assume positive
	skipge	tac2, mc0000(value)	; are we right?
	movei	tac1, "-"		; no
	idpb	tac1,t
	move	tac1, [point 6, tac2, 5]	; pointer to bytes
eb1:	ildb	value, tac1		; get byte
	movei	tac3,40
	idpb	tac3,t
	outdec				; output the byte
	tlne	tac1, 770000		; is it the last byte?
	jrst	eb1			; no
	popj	p,			; yes, we're through


ea0:	move	tac2, mc0000(value)	; must save pointer
	move	tac1, [point 6, tac2, 5]	; pointer to chars
ea1:	ildb	value, tac1		; get a char
	move	value, mixasc(value)	; convert to ascii
	idpb	value,t			; and output it
	tlne	tac1, 770000		; is is the last char?
	jrst	ea1			; no
	popj	p,			; yes
es00:	movei	tac1,40
	idpb	tac1,t
	move	value, mc0000(value)	; get value to output
ess0:	getsym				; get symbolic expression for it
	jumpe	tac3, es1		; tac3=0 → couldn't find a symbol
	caile	tac4, =100		; maximum offset of 100
	jrst	es1
	move	tac1, tac4		; save offset
	move	value, (tac3) 1		; put sequence into value
	move	value+1, (tac3) 2	; and value+1
	outnam				; output the name
	move	value, tac1		; now get the offset
	jumpe	value, es2		; zero offset → don't print any
	movei	tac1,"+"
	idpb	tac1,t
es1:	outdec				; either the offset or the entire value
es2:	popj	p,			; all done



ed00:	movei	tac1,40
	idpb	tac1,t
	move	value, mc0000(value)	; get the value to output
ed0:	movei	tac1, "+"		; assume positive
	jumpge	value, .+3		; right!
	movei	tac1, "-"		; wrong!!
	tlz	value, 400000		; turn off sign bit
	idpb	tac1,t			; output the sign
	outdec				; and then the value
	popj	p,			; all done
en0:	movei	tac1,40
	idpb	tac1,t
	movei	tac1, "+"		; assume positive
	skipge	tac2, mc0000(value)	; are we right?
	movei	tac1, "-"		; no
	idpb	tac1,t			; output the sign
	ldb	value, [point 12, tac2, 17]	; get address field
	outdec				; output it
	move	tac1, [point 6, tac2, 17]	; pointer to other fields
	movei	tac3,40
en1:	ildb	value, tac1		; get field
	idpb	tac3,t
	outdec				; output it
	tlne	tac1, 770000		; last field?
	jrst	en1			; no
	popj	p,			; yes
dposit:	addrc				; get address followed by ←
	pushj	p,fetch			; use fetch to kludge value in
					; case we're depositing into a break-
					; pointed location.
	move	spec2, value		; save address to deposit into
	wval				; get instruction to put there
	 jumpe	spec,bugerr		; registers may be deposited in.
	movem	value, mc0000(spec2)	; so put it there
	jrst	bugout			; all done
comment	⊗	BREAK and UBREAK are the places which handle
		Break and Unbreak commands
	⊗

break:	addr				; get address to set breakpoint
	jumpl	spec, bugerr		; don't allow register names for breakpoints
	addi	value, mc0000		; make it an absolute address
	movei	tac1, =39		; is it already in the table
	soj	tac1,
	camn	value, bptab(tac1)	; is it this entry?
	jrst	bugout			; yes → don't put it in again
	sojg	tac1, .-3		; check next entry
	movei	tac1, =39		; now look for blank place
	soj	tac1,
	skipl	bptab(tac1)		; is this entry zero?
	sojg	tac1, .-2		; no → try next one
	jumpl	tac1,	[outstr	[asciz	/too many breakpoints
/]					; tac1<0 → went all the way through table
			jrst	bugout]
	movem	value, bptab(tac1)	; now put this address into the table
	move	spec,(value)		; get original contents
	movem	spec,bptab+1(tac1)	; save
	hrli	tac1,-1
	movem	tac1,(value)		; replace cell with bp flag (this value
					; shouldn't happen to MIX programs.)
	jrst	bugout			; and return


ubreak:	inchar				; to check for line-feed
	cain	char, 100		; is U followed by <l-f>>
	jrst	ubr1			; yes → we delete all breakpoints
	addr				; get address to unbreak
	jumpl	spec, bugerr		; don't allow register names for unbreaks
	addi	value, mc0000		; make an absolute address
	movei	tac1, =39		; find it in table
	soj	tac1,
	camn	value, bptab(tac1)	; this entry?
	 jrst	ubr2
	sojg	tac1, .-3		; no → try next
	jrst	bugerr			; couldn't find it → so what

ubr1:	movei	tac1, =39		; want to delete all entries
	soj	tac1,
	skipl	spec,bptab(tac1)
	 pushj	p,ubr3
	sojg	tac1, .-3
	jrst	bugout			; and return

ubr2:	push	p,[bugout]
ubr:	move	spec,bptab(tac1)
ubr3:	move	value,bptab+1(tac1)
	movem	value,(spec)
	setzm	bptab+1(tac1)
	setom	bptab(tac1)
	popj	p,

↑bptab:	repeat	=20,	{-1 ↔ 0}		; this has the breakpoints
; first word = address (absolute). second word = contents
comment	⊗	JUMPER is (would you believe) what does the jumping
	⊗

jumper:	addr				; get address to jump to
	jumpl	spec, bugerr		; can't jump to a register name
	addi	value, mc0000		; make it an absolute address
	hrrm	value, acsave+pc	; put it in right half of  P.C.
	movsi	p, acsave		; now restore accumulators
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	jrst	mixmn1			; and resume operations
comment	⊗	XXXX is where we go to execute a particular instruction
	⊗

xxxx:	inchar				; to start off inst
	wval				; get the instruction
	 jrst	bugerr
	setzm	jbusx			; in case it is JBUS *
	movem	value, acsave+instr	; to get set to go
	movsi	p, acsave		; now we must restore the accumulators
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	tlo	flags, siflag		; set single-instruction flag
	jrst	mixmn2			; and begin execution
comment	⊗	EQUAL is used to show things in different styles
	⊗

equal:	inchar				; get descriptive character
	cain	char, 'd'		; decimal mode
	jrst	eqd			; yes
	cain	char, 's'		; symbolic mode
	jrst	eqs			; yes
	jrst	bugerr			; neither → error


eqd:	addr				; get address to consider
	jumpl	spec, bugerr		; there are no equivalences for registers
	outchr	[" "]
	jrst	ed0			; now go do it

eqs:	addr				; get address to consider
	jumpl	spec, bugerr		; there are no equivalences for registers
	outchr	[" "]
	jrst	ess0			; now go do it
comment	⊗	LF is where we display the next location
	⊗

lf:	aos	value, origin		; get next location
	skipl	tac5, mode		; now recall whatever mode we were in
	caile	tac5, 5			; within allowable range?
	 jrst	bugerr			; no → error
	pushj	p,fetch			; get MIX word
	pushj	p,setl			; get display line
	move	tac5,mode
	pushj	p,@modes(tac5)
	jrst	bugdis

BEND	MIXBUG
	SUBTTL	MIXLOK - I/O interlocking.

COMMENT	⊗	MIXLOK is the section that has the stuff do handle
		the i/o interlocking.  Basically, there are four
		subroutines:  RLOCK, WLOCK, RRLOCK, WWLOCK.  R and W
		assume a memory address (relative to MC0000) in MLOCK and skip
		if that address may be Read or Written.  RR and LL
		assume a range, with first address in the left half
		of MLOCK and the last address in the right half, and
		skip if every address in that range may be Read or Written.
	⊗



MLOCK:	0		; contains memory location (or range) under consideration

RLOCKT:			; table of devices which lock out a read attempt
CRDLOK:	-1
	0
	0
TINLOK:	-1
	0
	0
	0

WLOCKT:			; table of devices which lock out a write attempt
CPNLOK:	-1
	0
	0
PRNLOK:	-1
	0
	0
TOTLOK:	-1
	0
	0
	0

OPDEF	RLOCK	[PUSHJ P, .]
	SKIPA	11,[RLOCKT]

OPDEF	WLOCK	[PUSHJ P, .]
	MOVEI	11,WLOCKT

LOCK:	MOVE	10,(11)		;first entry is the value of EXTIME when the
				;device is ready
	CAMG	10,EXTIME	;has this time happened yet?
	JRST	LOKOK		;yes → this device doesn't lock us out
	MOVE	10,MLOCK	;this is the address under consideration
	CAML	10,1(11)	;does it come before first address in busy-range
	CAMLE	10,2(11)	;or after the last?
	JRST	LOKOK		;yes → then we aren't locked out
	POPJ	P,		;no → this device won't let us use this address
LOKOK:	ADDI	11,3		;go to next device in table
	SKIPE	(11)		;zero → no more devices
	JRST	LOCK		;go back for next device
	AOS	(P)		;no more devices → we can use this address
	POPJ	P,		;so skip on return


OPDEF	RRLOCK	[PUSHJ P, .]
	SKIPA	11, [RLOCKT]

OPDEF	WWLOCK	[PUSHJ P, .]
	MOVEI	11, WLOCKT

LLOCK:	MOVE	10,(11)		;check on EXTIME for this device
	CAMG	10,EXTIME
	JRST	LLOKOK		;device isn't busy
	HLRZ	10,MLOCK	;check first address in range
	CAML	10,2(11)	;is it higher than last locked-out address?
	JRST	LLOKOK		;yes → we're OK
	HRRZ	10,MLOCK	;check last address in range
	CAMG	10,1(11)	;is it lower than last locked-out address?
	JRST	LLOKOK		;yes → we're OK
	POPJ	P,		;no → some address in range is locked out
LLOKOK:	ADDI	11,3		;check next device
	SKIPE	(11)		;zero → no devices left
	JRST	LLOCK		;go back and check this device
	AOS	(P)		;no devices left → we can use this range
	POPJ	P,		;so skip on return
	SUBTTL	MIXMON - Central interpreter/monitor

;MIXMON is the central interpreter for MIX instruction words.

↑↑UPD0:	1
↑↑UPD1:	1
MIXMON:	SOSn	UPD1
	 pushj	p,ddupd		; update DDs
	HLLZS	10, ERRORC		; check on too many errors
;	TLNE	10, 200
;	JRST	[OUTSTR [ASCIZ ⊗
;JOB HALTED, TOO MANY ERRORS#⊗]
;		 JRST   HLT]
	INSKIP				; ANY INPUT FROM TTY → BACK TO BUTTON
	TLZE	FLAGS, SIFLAG		; SIFLAG → BACK TO BUTTON
	JRST	BUTTON			; RETURN CONTROL TO USER
MIXMN1:	HRRZ	10, PC			; PC>3999 → ERROR
	CAIL	10, MC0000
	CAILE	10, MC0000+(=3999)
	JRST	ZMOVER
	SUBI	10, MC0000		; save present value of PC
	MOVEM	10, ISPEC
	SETZM	JBUSX			; zero out JBUSX in case this is JBUS *
	MOVEM   10, MLOCK               ; now test for Read-interlock
	RLOCK
	JRST	ZPCLOK			; error
	MOVE	INSTR,@PC		; GET INSTRUCTION WORD
	hlro	10,instr
	aoje	10,mixbrk		; breakpoints have -1 in their LH, which
					; shouldn't occur in normal MIX code
mixbr2:	AOJ	PC,			; INCREMENT PROGRAM COUNTER
MIXMN2:	
	LDB	10,[POINT 6,INSTR,35]	;*RES* GET OP CODE
	SETZM	MSPEC			;ZERO OUT SAVED EFFECTIVE ADDRESS
	CAIE	10,5			;IS IT A SPECIAL INSTR WITH NO ADDRESS
	PUSHJ	P,MGET			; NO, GET EFECTIVE ADDRESS
	SKIPE	RUNC			; RUNC = 0 → no RUN file
	PUSHJ	P, DORUN
	AOS	EXTIME			; ONE MORE EXECUTE CYCLE
	MOVE	13, INSTR		; SET 13 TO OP-CODE
	ANDI	13, 77
	JRST	@OPLST(13)		; GO TO INSTRUCTION AREA

mixbrk:	camn	instr,brkflg		; same bp twice in a row ?
	 jrst	mixbr1			; yes → user typed continue
	movem	instr,brkflg		; no. set up flag.
	hrrzi	10,-mc0000(pc)
	outstr	[asciz/Breakpoint at /]
	pushj	p,typdec
	outstr	crlf
	jrst	button
mixbr1:	move	instr,bptab+1(instr)	; pick up original instruction
	setzm	brkflg			; zap flag
	jrst	mixbr2			; and continue.
brkflg:	0

typdec:	idivi	10,12
	jumpe	10,.+4
	hrlm	11,(p)
	pushj	p,.-3
	hlrz	11,(p)
	iori	11,60
	outchr	11
	popj	p,
OPLST:	NOP
	0+ADD
	0+SUB
	0+MUL
	0+DIV
	SPEC
	SHIFTS
	0+MOVE

	LDA
	LD1
	LD2
	LD3
	LD4
	LD5
	LD6
	LDX

	LDAN
	LD1N
	LD2N
	LD3N
	LD4N
	LD5N
	LD6N
	LDXN

	STA
	ST1
	ST2
	ST3
	ST4
	ST5
	ST6
	STX

	STJ
	STZ
	JBUS
	IOC
	0+IN
	0+OUT
	JRED
	JUMPS

	JA
	J1
	J2
	J3
	J4
	J5
	J6
	JX

	MODA
	MOD1
	MOD2
	MOD3
	MOD4
	MOD5
	MOD6
	MODX

	CMPA
	CMP1
	CMP2
	CMP3
	CMP4
	CMP5
	CMP6
	CMPX

COMMENT	⊗	Field specification:
			if M is in register 12
			   F-byte is in register 11
		      then "FPOINT(11)" is a byte pointer
			   to the appropriate byte(s)
			   in the core position addressed
			   by M.  Sign byte not included.
			   0 → illegal F-byte.
	⊗

↓FPOINT:	44B5
	FOR Y←1,5
	 {POINT  Y*6, MC0000(12), Y*6+5
	 }
	REPEAT	2, {0}
	FOR X←1,5
	 {FOR Y←0,5
	   {IFGE  Y-X, THEN
	     {POINT  (Y-X+1)*6, MC0000(12), Y*6+5
	     }
	    IFL   Y-X, THEN
	     {0
	     }
	   }
	  REPEAT  2, {0}
	 }
	REPEAT	20, {0}
COMMENT	⊗	Memory specification:
			this subroutine assumes present instruction
		in INSTR and puts M into register 12--
	⊗

OPDEF	GETM	[PUSHJ	P,.]	


MGET:
	LDB	12, [POINT  6, INSTR, 23]	; GET INDEX-BYTE
	jumpl	12,.+2				; INDEX<0 → ERROR
	CAILE	12, 6				; INDEX>6 → ERROR
	PUSHJ	P, YINDEX
	jumpe	12,.+2				; INDEX=0 → NO INDEXING
	MOVE	12, (12)			; INDEX≠0 → GET INDEX REGISTER
	TLZE	12, 400000			; SIGN=0 → SKIP
	MOVN	12,12				; SIGN=1 → NEGATE IT
	HLRZ	11, INSTR			; GET ADDRESS-BYTES
	TRZE	11, 400000			; SIGN=0 → SKIP
	MOVN	11,11				; SIGN=1 → NEGATE IT
	ADD	12, 11				; M ← AA+(I)
	MOVEM	12, MSPEC			; save M
	POPJ	P,

OPDEF	GETF	[PUSHJ  P, .]
	LDB	11, [POINT  6, INSTR, 29]
	SKIPN	FPOINT(11)
	PUSHJ	P, YFIELD
	MOVEM	11, SAVEF
	POPJ	P,


OPDEF	TESTR	[PUSHJ  P, .]
	JUMPE	13, .+2
	CAILE	13, 6
	POPJ	P,
	TDZE	10, [XWD 7777,770000]
	JRST	YIREG
	POPJ	P,


OPDEF	TESTM	[PUSHJ P, .]
	jumpl	12,.+2
	CAILE	12, =3999
	PUSHJ	P, YMOVER
	POPJ	P,

COMMENT	⊗	"Load" instructions.
	⊗

LDA:	LD1:	LD2:	LD3:	LD4:	LD5:	LD6:	LDX:
LDAN:	LD1N:	LD2N:	LD3N:	LD4N:	LD5N:	LD6N:	LDXN:

	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK		; test for Read-interlock
	RLOCK
	JRST	ZRLOCK			; error
	GETF
	LDB	10, FPOINT(11)			; GET FIELD FROM MEMORY
	CAILE	11, 5				; F≤5 → GET SIGN
	JRST	.+3
	SKIPGE	MC0000(12)			; MC0000(12)≥0 → SIGN=+
	tlo	10, (1B0)			; SIGN ← -
	CAILE	13, 17				; OP-CODE>15 → "LDN"
	TLC	10, 400000			; CHANGE SIGN
	ANDI	13, 7				; 13 ← REGISTER TO BE LOADED
	TESTR
	MOVEM	10, (13)			; LOAD REGISTER FROM 10
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER
COMMENT	⊗	"Store" instructions.
	⊗

STA:	ST1:	ST2:	ST3:	ST4:	ST5:	ST6:	STX:	

	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK		; test for Write-interlock
	WLOCK
	JRST	ZWLOCK			; error
	GETF
	ANDI	13, 7				; 13 ← REGISTER TO BE STORED
	MOVE	10, (13)			; STORE REGISTER TO 10
	TESTR
	DPB	10, FPOINT(11)			; STORE FIELD INTO MEMORY
	CAILE	11, 5				; F≤5 → STORE SIGN-BYTE
	JRST	.+3
	LDB	10, [POINT  6, (13), 5]		; GET SIGN FROM REGISTER
	DPB	10, [POINT  6, MC0000(12), 5]	; STORE SIGN
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


STJ:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK		; test for Write-interlock
	WLOCK
	JRST	ZWLOCK			; error
	GETF
	ANDI	13, 7				; 13 ← REGISTER TO BE STORED
	SETZ	10,				; CLEAR 10 IN PREPARATION
	DPB	RJ, FPOINT(11)			; STORE FIELD INTO MEMORY
	CAIG	11, 5				; F≤5 → STORE SIGN-BYTE
	DPB	10, [POINT  6, MC0000(12), 5]	; STORE SIGN
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


STZ:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK		; test for Write-interlock
	WLOCK
	JRST	ZWLOCK			; error
	GETF
	ANDI	13, 7				; 13 ← REGISTER TO BE STORED
	SETZ	10,				; CLEAR 10 IN PREPARATION
	DPB	10, FPOINT(11)			; STORE FIELD INTO MEMORY
	CAIG	11, 5				; F≤5 → STORE SIGN-BYTE
	DPB	10, [POINT  6, MC0000(12), 5]	; STORE SIGN
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER
COMMENT	⊗	"Arithmetic" instructions.
	⊗

ADD:	SUB:	

	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK			; test for Read-interlock
	RLOCK
	JRST	ZRLOCK				; error
	GETF
	LDB	10, FPOINT(11)			; GET FIELD FROM MEMORY
	CAILE	11, 5				; F≤5 → GET SIGN
	JRST	.+3
	SKIPGE	MC0000(12)			; MC0000(12)≥0 → SIGN=+
	MOVNS	10				; USE TWO'S COMPLEMENT FORM
	CAILE	13, 1				; OP-CODE≥1 → "SUB"
	MOVNS	10
	MOVE	11, RA				; SET UP 11 TO WORK
	TLZE	11, 400000			; SIGN≠0 → NEGATE 11
	MOVNS	11
	ADD	11, 10				; ADD
	JUMPGE	11, .+3				; 11≥0 → OK
	MOVNS	11				; 11<0 → FIX SIGN
	tlo	11,400000
	TLZE	11, 370000			; ANY OVERFLOW?
	TLO	FLAGS, OVFLAG			; YES → SET OVFLAG
	JUMPN	11, .+3				; 11=0 ∧ A<0 → CHANGE 11 TO -0
	JUMPGE	RA, .+2
	movsi	11,400000
	MOVE	RA, 11				; RESULTS TO REGISTER A
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


MUL:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK			; test for Read-interlock
	RLOCK
	JRST	ZRLOCK				; error
	GETF
	LDB	10, FPOINT(11)			; GET FIELD FROM MEMORY
	CAILE	11, 5				; F≤5 → GET SIGN
	JRST	.+3				; USE +
	SKIPGE	MC0000(12)			; MC0000≥0 → SIGN=+
	TLOA	12, 400000			; SIGN=- → MAKE 12 NEGATIVE
	SETZ	12,				; SIGN=+ → MAKE 12 ZERO
	MOVE	11, RA				; SET UP 11 TO WORK
	TLZE	11, 400000			; SIGN=- → CHANGE SIGN OF 12
	TLC	12, 400000
	MUL	10, 11				; MULTIPLY
	LDB	RX, [POINT  30, 11, 35]		; NUMERIC BITS INTO RX, CLEAR SIGN
	ASHC	10, 5				; SHIFT SO RIGHT BITS IN 10
	LDB	RA, [POINT  30, 10, 35]		; NUMERIC BITS INTO RA, CLEAR SIGN
	JUMPGE	12, .+3				; 12≥0 → SIGN OF RESULT IS +
	TLO	RX, 400000			; SIGNS OF RX, RA ARE -
	TLO	RA, 400000
	MOVEI	10, 11				; NINE MORE EXECUTE CYCLES
	ADDM	10, EXTIME			
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


DIV:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK			; test for Read-interlock
	RLOCK
	JRST	ZRLOCK				; error
	GETF
	LDB	13, FPOINT(11)			; GET FIELD FROM MEMORY
	SKIPGE	10, RA				; test sign of RA
	TLO	12, 600000			; reset sign bits in 12
	CAILE	11, 5				; F≤5 → use sign
	JRST	.+3
	SKIPGE	MC0000(12)			; if positive, no change
	TLC	12, 400000			; negative → change sign of RA
	CAML	10, 13				; |RA|≥|V| → OVERFLOW
	TLO	FLAGS, OVFLAG
	DPB	RX, [POINT  30, 11, 30]		; SET UP 11 FOR LOW-ORDER BITS
	ASHC	10, -5				; SHIFT INTO RIGHT POSITION FOR DIV
	DIV	10, 13				; DIVIDE
	TLNE	12, 400000			; CHECK QUOTIENT SIGN BIT
	TLO	10, 400000
	TLNE	12, 200000			; CHECK REMAINDER SIGN BIT
	TLO	11, 400000
	MOVE	RA, 10				; RA ← QUOTIENT
	MOVE	RX, 11				; RX ← REMAINDER
	MOVEI	10, 13				; ELEVEN MORE EXECUTE CYCLES
	ADDM	10, EXTIME
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


COMMENT	⊗	"Address transfer" insructions
	⊗

MODA:	MOD1:	MOD2:	MOD3:	MOD4:	MOD5:	MOD6:	MODX:

	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	LDB	11, [POINT  6, INSTR, 29]
	MOVEM	11,SAVEF			;*RES* SAVE FOR TRACE ROUTINE 
	CAIG	11, 3
	SKIPGE	11
	PUSHJ	P, YFIELD		; ILLEGAL F-FIELD
	ANDI	13, 7				; 13 ← REGISTER TO BE MODIFIED
	MOVE	10, (13)			; 10 ← SET UP 10 TO WORK
	TLZE	10, 400000			; SIGN≠0 → NEGATE 10
	MOVNS	10				; USE TWO'S COMPLEMENT FORM
	XCT	MODXCT(11)			; PERFORM APPROPRIATE OPERATION
	JUMPGE	10, .+3				; 10≥0 → OK
	MOVNS	10				; 10<0 → FIX SIGN
	tlo	10,400000
	TLZE	10, 370000			; ANY OVERFLOW?
	TLO	FLAGS, OVFLAG			; YES → SET FLAG
	JUMPN	10, .+3				; SPECIAL CONDITIONS
	XCT	M0XCT(11)
	movsi	10,400000		;	→ CHANGE 10 TO -0
	TESTR
	MOVEM	10, (13)			; RESULTS TO REG
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

MODXCT:	ADD	10, 12			; F=0 → INC...
	SUB	10, 12			; F=1 → DEC...
	MOVE	10, 12			; F=2 → ENT...
	MOVN	10, 12			; F=3 → ENN...

M0XCT:	SKIPGE	(13)			; F=0 → USE SIGN OF REG
	SKIPGE	(13)			; F=1 → USE SIGN OF REG
	SKIPGE	INSTR			; F=2 → USE SIGN OF INSTR
	SKIPGE	INSTR			; F=3 → USE SIGN OF INSTR

COMMENT	⊗	"Comparison" instructions.
	⊗

CMPA:	CMP1:	CMP2:	CMP3:	CMP4:	CMP5:	CMP6:	CMPX:

	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	MOVEM	12, MLOCK			; test for Read-interlock
	RLOCK
	JRST	ZRLOCK				; error
	GETF
	LDB	10, FPOINT(11)			; GET FIELD FROM MEMORY
	CAILE	11, 5				; F≤5 → GET SIGN
	JRST	.+3
	SKIPGE	MC0000(12)			; MC0000(12)≥0 → SIGN=+
	MOVNS	10				; USE TWO'S COMPLEMENT FORM
	ANDI	13, 7				; 13 ← REGISTER TO COMPARE
	MOVE	12, FPOINT(11)			; PUT FIELD-BYTE POINTER INTO 12
	TDC	12, [1000000+MC0000]		; POINTER ADDRESS ← "(13)"
COMMENT ⊗ THIS (↑) CLEVERNESS IS DUE TO DAN SWINEHART ⊗
	LDB	12, 12				; GET FIELD FROM REGISTER SHOWN IN 13
	CAILE	11, 5				; F≤5 → GET SIGN
	JRST	.+3
	SKIPGE	(13)				; (13)≥0 → SIGN=+
	MOVNS	12
	SUB	12, 10				; SUBTRACT TO GET COMPARE RESULT
	TLZ	FLAGS, GFLAG∨EFLAG∨LFLAG	; ZERO COMPARISON FLAGS
	JUMPLE	12, .+3				; ≤ → MOVE ON
	TLO	FLAGS, GFLAG			; > → SET FLAG
	JRST	.+4				; DONE
	JUMPL	12, .+2				; < → MOVE ON
	TLOA	FLAGS, EFLAG			; = → SET FLAG, SKIP
	TLO	FLAGS, LFLAG			; < → SET FLAG
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

COMMENT	⊗	"Jump" instructions.
	⊗

JUMPS:	MOVE	12,MSPEC
	TESTM
	LDB	11, [POINT  6, INSTR, 29]	; GET FIELD-BYTE
	MOVEM	11, SAVEF
	CAILE	11, 11				; F>9 → ERROR
	PUSHJ	P, Y2FIEL
	MOVE	11, SAVEF
	XCT	JMPXCT(11)			; PERFORM APPROPRIATE TEST
	JRST	MIXMON				; THERE WILL BE NO JUMP
JMP:	HRRZ	RJ, PC				; RJ ← PC-MC0000
	SUBI	RJ, MC0000
JSJ:	JUMPL	12, ZMOVER			; 12<0 → ERROR
						;	(12>3999 WILL BE FOUND LATER)
	ADDI	12, MC0000			; PC ← M+MC0000
	HRR	PC, 12
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

JMPXCT:	JRST	JMP			; F=0 → JMP
	JRST	JSJ			; F=1 → JSJ
	TLZN	FLAGS, OVFLAG		; F=2 → JOV
	TLZE	FLAGS, OVFLAG		; F=3 → JNOV
	TLNN	FLAGS, LFLAG		; F=4 → JL
	TLNN	FLAGS, EFLAG		; F=5 → JE
	TLNN	FLAGS, GFLAG		; F=6 → JG
	TLNN	FLAGS, GFLAG∨EFLAG	; F=7 → JGE
	TLNN	FLAGS, GFLAG∨LFLAG	; F=8 → JNE
	TLNN	FLAGS, LFLAG∨EFLAG	; F=9 → JLE


JA:	J1:	J2:	J3:	J4:	J5:	J6:	JX:

	MOVE	12,MSPEC
	TESTM
	LDB	11, [POINT  6, INSTR, 29]	; GET FIELD-BYTE
	MOVEM	11, SAVEF
	CAILE	11, 7				; F>7 → ERROR
	PUSHJ	P, Y2FIEL
	MOVE	11, SAVEF
	ANDI	13, 7				; 13 ← REGISTER TO TEST
	MOVE	10, (13)			; SET UP 10 TO WORK
	TLC	10, 400000			; CHECK FOR -0
	JUMPE	10, .+2				; NOT -0 SO RECOMPLEMENT
	TLC	10, 400000
	XCT	JXCT(11)			; TO MIXMON IF TEST FAILS
	JRST	JMP				; PERFORM THE JUMP
	JRST	MIXMON

JXCT:	JUMPGE	10, MIXMON		; F=0 → J.N
	JUMPN	10, MIXMON		; F=1 → J.Z
	JUMPLE	10, MIXMON		; F=2 → J.P
	JUMPL	10, MIXMON		; F=3 → J.NN
	JUMPE	10, MIXMON		; F=4 → J.NZ
	JUMPG	10, MIXMON		; F=5 → J.NP
	TRNN	10, 1			; F=6 → J.E
	TRNE	10, 1			; F=7 → J.O

COMMENT	⊗	Miscellaneous operators.
	⊗

MOVE:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	TESTM
	LDB	11, [POINT  6, INSTR, 29]	; GET FIELD-BYTE
	MOVEM	11, SAVEF
	JUMPE	11, MIXMON			; F=0 → LIKE A NOP
	HRLM	12, MLOCK			; test for read-interlock-range
	HRRM	12, MLOCK
	ADDM	11, MLOCK
	RRLOCK
	JRST	ZRLOCK
	MOVE	11,SAVEF		;*RES* RRLOCK CLOBBERS 11
	HRLM	R1, MLOCK			; test for write-interlock-range
	HRRM	R1, MLOCK
	ADDM	11, MLOCK
	WWLOCK
	JRST	ZWLOCK
	MOVE	11,SAVEF		;*RES* WWLOCK CLOBBERS 11
	MOVE	10, R1				; COMPUTE ADDRESS OF
	ADD	10, 11				;     FINAL DESTINATION
	SUBI	10, 1
	JUMPL	10, ZMOVER			; 10<0 → ERROR
	CAILE	10, =3999			; 10>3999 → ERROR
	JRST	ZMOVER
	JUMPL	R1, ZMOVER			; R1<0 → ERROR
	MOVE	13, R1				; 13 WILL HOLD BLT POINTER
	HRL	13, 12				; SOURCE ADDRESS IS M
	ADD	13, [XWD  MC0000, MC0000]	; RELOCATION (SORT OF)
	BLT	13, MC0000(10)			; PERFORM MOVE OPERATION
	ADD	R1, 11				; R1 ← R1+F
	LSH	11, 1				; 2*F MORE EXECUTE CYCLES
	ADDM	11, EXTIME
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


SHIFTS:	LDB	13, [POINT  6, INSTR, 29]	; GET FIELD-BYTE
	MOVEM	13, SAVEF
	CAIL	13, 0				; F<0 → ERROR
	CAILE	13, 7				; F>7 → ERROR
	PUSHJ	P, Y2FIEL
	MOVE	13, SAVEF
	MOVE	12,MSPEC			; GET MEMORY SPECIFICATION
	JUMPL	12, ZMOVER			; 12<0 → ERROR
	TRNE	13, 1				; 13 ODD → SHIFT RIGHT
	MOVNS	12				;     SO NEGATE FACTOR
	IMULI	12, 6				; 1 BYTE = 6 BITS
	CAILE	13, 1				; F=0,1 → SLA,SRA
	JRST	SAX
	MOVE	10, RA				; SET UP 10 TO WORK
	TLZ	10, 400000			; IGNORE SIGN
	LSH	10, (12)			; PERFORM SHIFT
	DPB	10, [POINT  30, RA, 35]		; PUT BACK SHIFTED BYTES
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

SAX:	MOVE	10, RA				; SET UP 10, 11 TO WORK
	MOVE	11, RX
	TLZ	10, 400000			; IGNORE SIGN
	LSH	11, 6				; CONCATENATE MEANINGFUL BYTES
	CAIGE	13, 6				; F=6,7 → SRB,SLB
	JRST	.+3				; OTHERWISE
	IDIVI	12, 6				; SO CHANGE BACK TO BITS
	JRST	.+3
	CAILE	13, 3				; F=2,3 → SLAX,SRAX
	JRST	SC
	LSHC	10, (12)			; PERFORM SHIFT
	LSH	11, -6				; BYTES TO NORMAL POSITIONS
	DPB	10, [POINT  30, RA, 35]		; PUT BACK SHIFTED BYTES
	DPB	11, [POINT  30, RX, 35]
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

SC:	ADDI	12, =30000			; MAKE 12>0 SO CAN USE
	IDIVI	12, =60				;     MOD(10)
	ROTC	10, (13)			; PERFORM SHIFT
	HRRZ	12, 13				; 6 BITS = 1 BYTE
	IDIVI	12, 6
	HRR	RX, 12				; USE RX FOR INDEXING
	MOVE	12, 10				; 12,13 USED TO SAVE BYTES
	MOVE	13, 11				;     WHICH ARE CORRECT
	AND	12, ROTA(RX)
	AND	13, ROTX(RX)
	ROTC	10, 14				; ROTATE TO GET REST OF GOOD BYTES
	ANDCM	10, ROTA(RX)			; MASK OUT BAD BYTES
	ANDCM	11, ROTX(RX)
	OR	10, 12				; PUT GOOD PARTS TOGETHER
	OR	11, 13
	LSH	11, -6				; BYTES TO NORMAL POSITIONS
	DPB	10, [POINT  30, RA, 35]		; PUT BACK SHIFTED BYTES
	DPB	11, [POINT  30, RX, 35]
	AOS	EXTIME				; ONE MORE EXECUTE CYCLE
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

ROTA:	XWD  7777,777777			; MASKING TABLES FOR SLC AND SRC
	XWD  7777,777777
	XWD  7777,777777
	XWD  7777,777777
	XWD  7777,777777
	XWD  7777,777777
	XWD  7777,777700
	XWD  7777,770000
	XWD  7777,000000
	XWD  7700,000000
ROTX:	XWD  777777,777700
	XWD  777777,770000
	XWD  777777,000000
	XWD  777700,000000
	XWD  770000,000000
	XWD  000000,000000
	XWD  000000,000000
	XWD  000000,000000
	XWD  000000,000000
	XWD  000000,000000


NOP:	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER


SPEC:	LDB	12, [POINT  6, INSTR, 29]	; GET FIELD-BYTE
	MOVEM	12, SAVEF
	CAIL	12, 0
	CAILE	12, 2
	PUSHJ	P, Y2FIEL
	MOVE	12, SAVEF
	CAIE	12, 2				; F=2 → HLT
	JRST	.+5
HLT:	OUTSTR	[ASCIZ  ⊗
#HALT#⊗]
	SKIPE	RUNC				; RUNC=0 → NO RUN FILE
	JRST	ENDRUN
	JRST	BUTTON				; RETURN CONTROL TO USER
	JUMPN	12, CHAR			; F>0 → CHAR
NUM:	SETZ	12,				; CLEAR 12 TO ACCUMULATE RESULT
	HRRI	13, 0				; INITIALIZE POINTER ADDRESS
	HRLI	13, 360600			; INITIALIZE BYTE INDICATORS
	ILDB	10, 13				; GET CHARACTER
	IDIVI	10, 12				; GET MOD(10)
	IMULI	12, 12				; ACCUMULATE SUM
	ADD	12, 11
	TLNE	13, 770000			; FINISHED WITH BATCH OF 5 BYTES?
	JRST	.-5				; NO → GET SOME MORE
	TRON	13, 7				; WAS THIS RX?
	JRST	.-10				; NO, BUT NOW IT IS!!!
	TLZE	12, 370000			; DONE → TEST FOR OVERFLOWS
	TLO	FLAGS, OVFLAG			; YES → SET FLAG
	DPB	12, [POINT  30, RA, 35]		; PUT NUM INTO RA
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER
CHAR:	MOVE	10, RA				; INITIALIZE 10
	TLZ	10, 400000			; IGNORE SIGN
	MOVEI	13, 1				; LOOP COUNTER
	SETZ	12,				; ZERO OUT WORK REGISTER
	IDIVI	10, 12				; GET REMAINDER
	ADDI	11, 36				; CONVERT TO CHARACTER CODE
	OR	12, 11				; PUT CHAR INTO WORK REGISTER
	ROT	12, -6				; SHIFT RIGHT ONE BYTE
	TRNN	12, 7700			; TEST FOR 5 BYTES
	JRST	.-5				; NO → GET MORE
	LSH	12, -6				; PUT INTO RIGHT POSITION
	DPB	12, CPOINT(13)			; PUT INTO RX OR RA
	SOJGE	13, .-11			; ONE MORE TIME?
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER
CPOINT:	POINT	30, RA, 35
	POINT	30, RX, 35

PATCH:	BLOCK	=100			;*RES*

	SUBTTL	MIXIO - I/O button routines
crdpag:	0					; 0 iff on first page of data file
QREAD:	SKIPE	CRDBLK				; 0 → NOT INITED
	JRST	QRD1
	INIT	10,
	SIXBIT	/DSK/
	CRDBLK+1
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR CARD READER INPUT: ⊗]
	PUSHJ	P,FINFO				;GET FILE DATA
	MOVE	10, [XWD  BLK, CRDBLK+4]	; PUT DATA IN CRDBLK
	BLT	10, CRDBLK+7
	LOOKUP	10, CRDBLK+4			; LOOKUP FILE
	JRST	.-5				; ERROR → TRY AGAIN
	inbuf	10,
	setzm	crdpag				; start at page 0.
	AOS	CRDBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QRD1:	OUTSTR	[ASCIZ ⊗READ FILE ALREADY OPEN⊗]  ;*RES* 
	JRST	QBUTN				;*RES*

QREADX:	RELEAS	10, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	CRDBLK				; RESET I/O STATUS WORD
	JRST	BUTTON


QPUNCH:	SKIPE	CPNBLK				; 0 → NOT INITED
	JRST	QPN1
	INIT	11, 10				; INIT IN IMAGE MORE
	SIXBIT	/DSK/
	XWD	CPNBLK+1, 0
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR CARD PUNCH OUTPUT: ⊗]
	PUSHJ	P,FINFO				; GET FILE DATA
	MOVE	10, [XWD  BLK, CPNBLK+4]	; PUT DATA IN CPNBLK
	BLT	10, CPNBLK+7
	ENTER	11, CPNBLK+4			; ENTER FILE
	JRST	.-5				; ERROR → TRY AGAIN
	outbuf	11,
	AOS	CPNBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QPN1:	OUTSTR	[ASCIZ ⊗PUNCH FILE ALREADY OPEN⊗] ;*RES*
	JRST	QBUTN				;*RES*

QPNCHX:	RELEAS	11, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	CPNBLK				; RESET I/O STATUS WORD
	JRST	BUTTON


QPRINT:	SKIPE	PRNBLK				; 0 → NOT INITED
	JRST	QPR1
	INIT	12, 10				; INIT IN IMAGE MORE
	SIXBIT	/DSK/
	XWD	PRNBLK+1, 0
	JRST	ZDISK				; ERROR RETURN
	PUSHJ	P,RESCN				;*RES* LOOK FOR NAME ON PREV LINE
	PUSHJ	P,FINFI2			;*RES* LOOK IT UP
	JRST	.+3				;*RES* RESCN SKIPS 2 IF NO ARG
	OUTSTR	[ASCIZ	⊗FILE FOR PRINTER OUTPUT: ⊗]
	PUSHJ	P,FINFO				;GET FILE DATA
	MOVE	10, [XWD  BLK, PRNBLK+4]	; PUT DATA IN PRNBLK
	BLT	10, PRNBLK+7
	ENTER	12, PRNBLK+4			; ENTER FILE
	JRST	.-5				; ERROR → TRY AGAIN
	outbuf	12,
	AOS	PRNBLK				; I/0 STATUS WORD ← +1
	JRST	BUTTON
QPR1:	OUTSTR	[ASCIZ ⊗PRINT FILE ALREADY OPEN⊗] ;*RES*
	JRST	QBUTN				;*RES*

QPRNTX:	RELEAS	12, 0				; CLOSE AND RELEAS CHANNEL
	SETZM	PRNBLK				; RESET I/O STATUS WORD
	JRST	BUTTON

QBUTN:	INCHWL	10				;*RES* READ REST OF LINE 
	CAIE	10,12				;*RES*  UP TO THE LF
	JRST	.-2
	JRST	BUTTON				;*RES* THEN GO TO BUTTON

COMMENT	⊗	"Input-output" operations.

	At present (6-25-70), the only devices planned for this MIX
	machine are the following:
		card reader	`CRD'  F=16  chan=10
		card punch	`CPN'  F=17  chan=11
		printer		`PRN'  F=18  chan=12
		typewriter(in)	`TIN'  F=19  chan=13
		typewriter(out)	`TOT'  F=19  chan=14

	The simulation of i/o for CRD, CPN, PRN will be done through the
	use of disk files.

	Each device will have a device block of 8 words, containing
	the following information:
		word   1	an i/o status word
		words  2-4	i/o buffer for the system
		words  5-8	file info for LOOKUP or ENTER

	TIN and TOT will be done directly to and from the teletype.
	In addition, a copy of everything printed on the teletype
	during each use of MIXSIM will be saved on a file called
	MIXTTY.  This will enable the user to obtain hard copies of
	everything.

	⊗

COMMENT	⊗	This subroutine takes the MIX character in register 10
		and puts it into the appropriate place in MIXBUF (using
		a byte pointer in 11).  If this fills MIXBUF, the routine
		moves MIXBUF to the address in MIXAD, increments MIXAD,
		resets the byte pointer in 11, and zeros out MIXBUF.
			Called by "CTOMIX"
	⊗

OPDEF	CTOMIX	[PUSHJ  P, .]
	IDPB	10, 11				; PUT BYTE INTO MIXBUF
	TLNE	11, 770000			; LAST BYTE IN MIXBUF?
	POPJ	P,				; NO → RETURN
	MOVE	10, MIXBUF			; YES → PUT INTO MIX CORE
	MOVEM	10, @MIXAD
	AOS	MIXAD				; INCREMENT MIXAD
	MOVE	11, [POINT  6, MIXBUF, 5]	; RESET BYTE POINTER
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	POPJ	P,				; RETURN

COMMENT	⊗	This subroutine takes the MIX word in register 10
		and moves it to the address in MIXAD.
			Called by "WTOMIX"
	⊗

OPDEF	WTOMIX	[PUSHJ	P, .]
	MOVEM	10, @MIXAD			; PUT INTO MIX CORE
	AOS	MIXAD				; INCREMENT MIXAD
	POPJ	P,				; RETURN


COMMENT	⊗	This subroutine is similar to CTOMIX, but instead of
		putting the characters into MIXBUF, it takes them out
		(resetting MIXBUF and MIXAD when necessary).
			Called by "CFRMIX"
	⊗

OPDEF	CFRMIX	[PUSHJ  P, .]
	TLNE	11, 770000			; LAST BYTE IN MIXBUF?
	JRST	.+5				; NO
	MOVE	10, @MIXAD			; YES → GET NEXT ONE
	MOVEM	10, MIXBUF
	AOS	MIXAD				; INCREMENT MIXAD
	MOVE	11, [POINT  6, MIXBUF, 5]	; RESET POINTER
	ILDB	10, 11				; GET NEXT CHARACTER
	POPJ	P,				; RETURN

COMMENT	⊗	This is similarly analagous to WTOMIX.
			Called by "WFRMIX"
	⊗

OPDEF	WFRMIX	[PUSHJ  P, .]
	MOVE	10, @MIXAD			; GET NEXT WORD
	AOS	MIXAD				; INCREMENT MIXAD
	POPJ	P,				; RETURN







COMMENT ⊗  The IN instruction  ⊗

IN:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATIONS
	ADDI	12, MC0000			; RELOCATE SO ADDRESSES MIX-CORE
	MOVEM	12, MIXAD			; INITIALIZE MIXAD
	LDB	11, [POINT 6, INSTR, 29]	; GET FIELD-BYTE
	CAILE	11, =19				; UNIT NUMBER MUST BE ≤19
	JRST	ZUNIT				; ERROR
	SKIPG	13, UNIN(11)			; 13 ← CHANNEL NUMBER AND
	JRST	ZUNIT				;	ERROR IF ZERO
	HLRZ	10, LOCK1(11)		; first we wait for this device to finish anything
	JUMPE	10, .+4			; no input on this device
	MOVE	10, (10)		; get time for finishing input
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; no → make it happen
	HRRZ	10, LOCK1(11)
	JUMPE	10, .+4			; no output on this device
	MOVE	10, (10)		; get time for finishing output
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; now it has
	HRLZ	10, 12			; now see if any interlocks on the range to work with
	HRR	10, LOCK0(11)
	ADD	10, 12
	SUB	10, [XWD MC0000, MC0000]
	MOVEM	10, MLOCK		; now MLOCK has range descriptor
	WWLOCK				; test whether it's OK to use this range
	JRST	ZWLOCK			; no it isn't
	LDB	11, [POINT 6, INSTR, 29]
	HLRZ	10, LOCK1(11)			; add device to RLOCKT for read-interlock
	JUMPE	10, IN1				; zero → this device doesn't get entered (should never take this jump)
	MOVEM	10, LOCK2			; save base address of entry in table
	HLRZ	10, LOCK0(11)			; this gives total interlock time
	ADD	10, EXTIME			; so this is time when device is finally ready
	MOVEM	10, @LOCK2			; a fact we should remember
	AOS	LOCK2				; for next part of table entry
	MOVE	10, MIXAD			; this is base address of locked-out range
	SUBI	10, MC0000			; make it relative to MC0000
	MOVEM	10, @LOCK2			; and remember it
	AOS	LOCK2				; get ready for next part of entry
	ADD	10, LOCK0(11)			; this gives final address of range
	HRRZS	10				; get rid of garbage in left half
	MOVEM	10, @LOCK2			; and remember this too
IN1:	MOVE	11, [POINT  6, MIXBUF, 5]	; INITIALIZE BYTE POINTER TO MIXBUF
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	JRST	@INAD(13)			; GO TO APPROPRIATE ADDRESS

INAD:	0
	0
	0
	0
	0
	0
	0
	0
	INCRD
	0
	0
	INTIN
	0
	0
	0
	0


COMMENT ⊗  The OUT instruction  ⊗

OUT:	MOVE	12,MSPEC			; GET MEMORY SPECIFICATIONS
	ADDI	12, MC0000			; RELOCATE SO ADDRESSES MIX-CORE
	MOVEM	12, MIXAD			; INITIALIZE MIXAD
	LDB	11, [POINT 6, INSTR, 29]	; GET FIELD-BYTE
	CAILE	11, =19				; UNIT NUMBER MUST BE ≤19
	JRST	ZUNIT				; ERROR
	SKIPG	13, UNOUT(11)			; 13 ← CHANNEL NUMBER AND
	JRST	ZUNIT				;	ERROR IF ZERO
	HLRZ	10, LOCK1(11)		; first we wait for this device to finish anything
	JUMPE	10, .+4			; no input on this device
	MOVE	10, (10)		; get time for finishing input
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; no → make it happen
	HRRZ	10, LOCK1(11)
	JUMPE	10, .+4			; no output on this device
	MOVE	10, (10)		; get time for finishing output
	CAMLE	10, EXTIME		; has it happened?
	MOVEM	10, EXTIME		; now it has
	HRLZ	10, 12			; now see if any interlocks on the range to work with
	HRR	10, LOCK0(11)
	ADD	10, 12
	SUB	10, [XWD MC0000, MC0000]
	MOVEM	10, MLOCK		; now MLOCK has range descriptor
	RRLOCK				; test whether it's OK to use this range
	JRST	ZRLOCK			; no it isn't
	LDB	11, [POINT 6, INSTR, 29]
	HRRZ	10, LOCK1(11)			; add device to RLOCKT for read-interlock
	JUMPE	10, OUT1				; zero → this device doesn't get entered (should never take this jump)
	MOVEM	10, LOCK2			; save base address of entry in table
	HLRZ	10, LOCK0(11)			; this gives total interlock time
	ADD	10, EXTIME			; so this is time when device is finally ready
	MOVEM	10, @LOCK2			; a fact we should remember
	AOS	LOCK2				; for next part of table entry
	MOVE	10, MIXAD			; this is base address of locked-out range
	SUBI	10, MC0000			; make it relative to MC0000
	MOVEM	10, @LOCK2			; and remember it
	AOS	LOCK2				; get ready for next part of entry
	ADD	10, LOCK0(11)			; this gives final address of range
	HRRZS	10				; get rid of garbage in left half
	MOVEM	10, @LOCK2			; and remember this too
OUT1:	MOVE	11, [POINT  6, MIXBUF, 5]	; INITIALIZE BYTE POINTER TO MIXBUF
	SETZM	MIXBUF				; ZERO OUT MIXBUF
	JRST	@OUTAD(13)			; GO TO APPROPRIATE ADDRESS

OUTAD:	0
	0
	0
	0
	0
	0
	0
	0
	0
	OUTCPN
	OUTPRN
	0
	OUTTOT
	0
	0
	0


COMMENT	⊗	These tables are used to convert the F unit number
		to i/o channels.  A `0' indicates that that form of
		i/o cannot be done with that unit.
	⊗

UNIN:	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	10	; CARD READER
	0	; CARD PUNCH CANNOT DO INPUT
	0	; PRINTER CANNTO DO INPUT
	13	; TYPEWRITER

UNOUT:	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0	; CARD READER CANNOT DO OUTPUT
	11	; CARD PUNCH
	12	; PRINTER
	14	; TYPEWRITER



MIXAD:	0		; CONTAINS ADDRESS OF NEXT MIX WORD TO WORRY ABOUT
MIXBUF:	0		; BUFFER FOR MIX WORDS
IOBUF:	0		; BUFFER FOR I/O DEVICES
COUNT:	0



LOCK0:	repeat =16	{0}			; this table has interlock times and record lengths
	XWD	=1000, =15			; CRD: 1000u and 16 words
	XWD	=1000, =15			; CPN: 1000u and 16 words
	XWD	=750, =23			; PRN:  750u and 24 words
	XWD	=2000, =13			; TIN,TOT: 2000u and 14 words

LOCK1:	repeat =16	{0}			; this table has address for interlock tables
	XWD	CRDLOK, 0			; CRD: read-interlock
	XWD	0, CPNLOK			; CPN: write-interlock
	XWD	0, PRNLOK			; PRN: write-interlock
	XWD	TINLOK, TOTLOK			; Typ: both read and write

LOCK2:	0					; this is just used for temporary stoarage
COMMENT	⊗	These are the device specific sections.
	⊗



; ******	CARD READER
CRDBLK:	BLOCK	10

INCRD:	SKIPN	CRDBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	MOVEI	10, =80				; SET UP COUNTER FOR CHARACTERS
	MOVEM	10, COUNT
incrd1:	PUSHJ	P, GETbyt			; YES → GET NEXT byte
	CAIN	10, 15				; CARRIAGE-RETURN →
	 JRST	incrd2				;	FINISH LINE WITH BLANKS
	MOVE	10, ASCMIX(10)			; CONVERT TO MIX CODE
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	 jrst	incrd1
	JRST	incrd3				; NOW GO TO END OF LINE
incrd2:	SETZ	10,				; MIX CODE FOR <BLANK> IS 00
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-3
incrd3:	PUSHJ	P, GETbyt			; YES → GET NEXT byte
	CAIE	10, 12				; KEEP TRYING UNTIL LINE-FEED
	 JRST	.-2
	SETZM	CRDBLK				; I/O STATUS WORD ← -1
	SOS	CRDBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

GETbyt:	SOSG	CRDBLK+3			; DECREMENT CHARACTER COUNT
	IN	10,				; COUNT EXHAUSTED, NEXT BUFFER
	JRST	.+4				; OK, SO CONTINUE
	STATZ	10, 20000			; TEST WHETHER ERROR WAS EOF
	JRST	ZEOF				; YES
	JRST	ZINOUT				; SOME OTHER I/O ERROR
	ILDB	10, CRDBLK+2			; GET INPUT WORD
	JUMPE	10,GETbyt			;*RES* IGNORE NULLS AT END OF RECORD
	move	12,@crdblk+2			; pick up next word
	skipe	crdpag				; still on first page ?
	 jrst	getby1				; no.
	setom	crdpag				; only make this test once.
	move	12,@crdblk+2
	came	12,[ascii/COMME/]
	 popj	p,
	aos	crdblk+2
	move	12,@crdblk+2
	sos	crdblk+2
	came	12,[ascii/NT ⊗ /]
	 popj	p,
	sosg	crdblk+3			; we have an E directory page.
	 input	10,
	ildb	12,crdblk+2
	caie	12,14
	 jrst	.-4
	jrst	getbyt
getby1:	trnn	12,1				; SOS linenum or like ?
	 popj	p,				; No.
	aos	crdblk+2			; Yes, ignore.
	movni	12,5
	addm	12,crdblk+3
	jrst	getbyt



	; ******	CARD PUNCH
CPNBLK:	BLOCK	10

OUTCPN:	SKIPN	CPNBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	MOVEI	10, =80				; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	IDPB	10, 12				; PUT INTO IOBUF
	TLNN	12, 760000			; LAST BYTE IN IOBUF?
	PUSHJ	P, PUTWRD			; YES → OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	IDPB	10, 12
	MOVEI	10, 12
	IDPB	10, 12
	PUSHJ	P, PUTWRD
	SETZM	CPNBLK				; I/O STATUS WORD ← -1
	SOS	CPNBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

PUTWRD:	SOSG	CPNBLK+3			; DECREMENT CHARACTER COUNT
	OUT	11,				; OUTPUT THIS BUFFER
	SKIPA					; SUCCESS
	JRST	ZINOUT				; ERROR
	MOVE	10, IOBUF			; GET OUTPUT WORD
	IDPB	10, CPNBLK+2			; PUT ONTO FILE
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	POPJ	P,				; RETURN



; ******	TYPEWRITER (IN)
TINBLK:	BLOCK	10

INTIN:	MOVEI	10, =70				; SET UP COUNTER
	MOVEM	10, COUNT
	INCHWL	10				; GET FIRST CHAR OF LINE
	SKIPA					; FOR FIRST TIME
	INCHRW	10				; GET NEXT CHAR
	CAIN	10, 15				; CARRIAGE-RETURN →
	JRST	.+6				;	FINISH LINE WITH BLANKS
	MOVE	10, ASCMIX(10)			; CONVERT TO MIX CODE
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	JRST	.+5				; NOW GO TO END OF LINE
	SETZ	10,				; MIX CODE FOR <BLANK> IS 00
	CTOMIX
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-3
	INCHRW	10				; KEEP TRYING UNTIL LINE-FEED
	CAIE	10, 12
	JRST	.-2
	SETZM	TINBLK				; I/O STATUS WORD ← -1
	SOS	TINBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER



	; ******	TYPEWRITER (OUT)
TOTBLK:	BLOCK	10

OUTTOT:	MOVEI	10, =70				; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	OUTCHR	10				; OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-4
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	OUTCHR	10
	MOVEI	10, 12
	OUTCHR	10
	SETZM	TOTBLK				; I/O STATUS WORD ← -1
	SOS	TOTBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER



	; ******	PRINTER
PRNBLK:	BLOCK	10

OUTPRN:	SKIPN	PRNBLK				; I/O STATUS WORD = 0
	JRST	ZIOBEG				;	→ NOT INITED YET
	MOVEI	10, =120			; SET UP COUNTER FOR CHARS
	MOVEM	10, COUNT
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	SETZ	11,				; FIX 11 SO CFRMIX WORKS FIRST TIME
	CFRMIX
	MOVE	10, MIXASC(10)			; CONVERT TO ASCII CODE
	IDPB	10, 12				; PUT INTO IOBUF
	TLNN	12, 760000			; LAST BYTE IN IOBUF?
	PUSHJ	P, PRNWRD			; YES → OUTPUT IT
	SOSE	COUNT				; BACK FOR MORE
	JRST	.-6
	MOVEI	10, 15				; NOW OUTPUT C-R, L-F
	IDPB	10, 12
	SKIPN	NOJECT				;*RES* SEE IF PRINT OVER PERF
	JRST	.+6				;*RES* NO
	MOVEI	10,177				;*RES* 
	IDPB	10,12				;*RES* LPT LIKES 177&21 FOR LF ALSO
	MOVEI	10,21				;*RES* 
	IDPB	10,12				;*RES* 
	JRST	.+3				;*RES* 
	MOVEI	10, 12
	IDPB	10, 12
	PUSHJ	P, PRNWRD
	SETZM	PRNBLK				; I/O STATUS WORD ← -1
	SOS	PRNBLK
	JRST	MIXMON				; RETURN TO INSTRUCTION INTERPRETER

PRNWRD:	SOSG	PRNBLK+3			; DECREMENT CHARACTER COUNT
	OUT	12,				; OUTPUT THIS BUFFER
	SKIPA					; SUCCESS
	JRST	ZINOUT				; ERROR
	MOVE	10, IOBUF			; GET OUTPUT WORD
	IDPB	10, PRNBLK+2			; PUT ONTO FILE
	SETZM	IOBUF				; ZERO OUT IOBUF
	MOVE	12, [POINT  7, IOBUF]		; INITIALIZE BYTE POINTER
	POPJ	P,				; RETURN




;	these are the other i/o related operations


IOC:	MOVE	12,MSPEC		; the only one we'll allow is IOC 0,(18)
	JUMPN	12, ZIOC		; so if M in non-zero, it's an error
	LDB	11, [POINT 6, INSTR, 29]	; now get F-field
	CAIE	11, =18			; if F 18?
	JRST	ZIOC			; no → error
	MOVE	10, PRNLOK		; wait until printer is finished
	CAMLE	10, EXTIME		; do this by changing EXTIME if necessary
	MOVEM	10, EXTIME		; it is necessary
	MOVE	10, EXTIME		; now we must interlock the printer for the form-feed
	ADDI	10, =1000		; we will use 1000u
	MOVEM	10, PRNLOK		; establish interlock time
	SETOM	PRNLOK+1		; use range -1:-1
	SETOM	PRNLOK+2
	MOVEI	10, 6430		;*RES* this is a carriage-return, form-feed
	MOVEM	10, IOBUF		; so this is <null><null><null><c-r><f-f>
	SKIPN	PRNBLK			; is printer inited?
	JRST	ZIOBEG			; no → txis is an error
	PUSHJ	P,PRNWRD		;*RES* now send the new page stuff
	SETOM	PRNBLK			; i/o status word ← -1
	JRST	MIXMON			; and return to instruction interpreter



JBUS:	MOVE	12,MSPEC		; first we see whether it is JBUS *
	CAMN	12, ISPEC		; does it match address of present instruction
	JRST	JBUS1			; yes → special case
	MOVSI	10, (<CAMGE 10,>)	; no → use same routine as JRED
	JRST	JRB
JBUS1:	LDB	11, [POINT 6, INSTR, 29]	; get F-field
	CAIL	11, =16			; is it a legal unit?
	CAILE	11, =19
	JRST	ZDEV			; no → error
	MOVE	10, EXTIME		; save EXTIME so we get a count of number of executions
	MOVEM	10, JBUSX
	HLRZ	10, LOCK1(11)		; get address to check for input busy
	JUMPE	10, .+4			; no such address → don't check
	MOVE	10, (10)		; get time when device is finished
	CAML	10, EXTIME		; and see whether it has happened
	MOVEM	10, EXTIME		; no → change so it has
	HRRZ	10, LOCK1(11)		; address to check for output busy
	JUMPE	10, .+4			; no address → don't check
	MOVE	10, (10)		; get time device is finished
	CAML	10, EXTIME		; and see whether time has come pass
	MOVEM	10, EXTIME		; no → now it has
	MOVE	10, EXTIME		; calculate number of executions
	SUBM	10, JBUSX		; new EXTIME - old EXTIME
	SKIPG	JBUSX			; any at all?
	SETZM	JBUSX			; no → make sure it's zero
	JRST	MIXMON			; so device is no longer busy



JRED:	MOVSI	10, (<CAML 10,>)	; so we can use same routine for JBUS, JRED

JRB:	HLLM	10, JRB1		; fix so we do the right compares
	HLLM	10, JRB2
	MOVE	12,MSPEC		; get address to jump to
	TESTM				; is is valid?
	LDB	11, [POINT 6, INSTR, 29]	; get F-field
	CAIL	11, =16			; is it valid?
	CAILE	11, =19
	JRST	ZDEV			; no → error
	HLRZ	10, LOCK1(11)		; test for input busy
	JUMPE	10, .+4			; no input
	MOVE	10, (10)		; get execution time for finishing
JRB1:		EXTIME			; this is the crucial compare
	JRST	MIXMON			; don't want to jump
	HRRZ	10, LOCK1(11)		; test for output busy
	JUMPE	10, .+4
	MOVE	10, (10)
JRB2:		EXTIME			; another crucial compare
	JRST	MIXMON			; don't want to jump
	JRST	JMP			; we do want to jump



JBUSX:	0				; this will contain the number of executions of JBUS *

↓NOMIX←←1; Inhibit assembly of all but essential parts of MIXAL.